release: v4.8.10 user-configurable STUN/TURN servers
- add header gear + connection-screen entry points to Advanced network settings - render the ICE settings modal at the app root (reachable from any screen via event) - remove the standalone relay-only toggle/description from the start screen (relay-only now lives in the advanced settings panel) - fix crash from referencing main-component state inside EnhancedConnectionSetup - bump version to 4.8.10 across header, manifest, README, init message, disclaimer - document the feature in CHANGELOG and README
This commit is contained in:
@@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v4.8.10 — User-configurable STUN/TURN servers
|
||||||
|
|
||||||
|
Adds optional, advanced control over WebRTC connectivity for power and privacy-focused users. Public servers remain the zero-config default.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- "Advanced network settings" panel (header gear icon and the connection-creation screen) where users can supply their own STUN/TURN servers instead of the bundled public defaults.
|
||||||
|
- Allowlist-based validation of user input: only `stun:`/`stuns:`/`turn:`/`turns:` URLs with valid hosts are accepted; `javascript:`, `data:`, `http(s):`, `ws(s):`, control characters, and oversized input are rejected before anything reaches `RTCPeerConnection`.
|
||||||
|
- Optional on-device persistence, encrypted at rest with a non-extractable AES-GCM device key in IndexedDB, with an explicit save prompt and a "Forget saved" action.
|
||||||
|
- "Test servers" button that gathers ICE candidates against the entered configuration and reports STUN/TURN reachability.
|
||||||
|
- Privacy guidance in the panel: a TURN relay sees peer IPs and traffic timing (never message contents), so only a trusted/self-hosted relay improves privacy.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Relay-only privacy mode now lives in the advanced settings panel. The standalone relay-only toggle on the start screen was removed to declutter the initial view.
|
||||||
|
- Server selection priority: user custom servers > operator override (`config/ice-servers.js`) > built-in public defaults.
|
||||||
|
|
||||||
## v4.8.9 — Security hardening patch
|
## v4.8.9 — Security hardening patch
|
||||||
|
|
||||||
This release closes a vulnerable dependency, removes committed TURN credentials, and tightens production logging.
|
This release closes a vulnerable dependency, removes committed TURN credentials, and tightens production logging.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# SecureBit.chat v4.8.9
|
# SecureBit.chat v4.8.10
|
||||||
|
|
||||||
SecureBit.chat is a browser-based peer-to-peer chat application built on WebRTC and Web Crypto APIs. It is designed for direct encrypted communication, explicit peer verification, and a small operational footprint without account registration or server-side message storage.
|
SecureBit.chat is a browser-based peer-to-peer chat application built on WebRTC and Web Crypto APIs. It is designed for direct encrypted communication, explicit peer verification, and a small operational footprint without account registration or server-side message storage.
|
||||||
|
|
||||||
@@ -15,14 +15,17 @@ SecureBit.chat uses:
|
|||||||
|
|
||||||
A session is not treated as verified until both peers complete the interactive SAS flow. Each user must compare the displayed code with the peer through an out-of-band channel and enter the matching code manually. Three failed SAS attempts terminate the session.
|
A session is not treated as verified until both peers complete the interactive SAS flow. Each user must compare the displayed code with the peer through an out-of-band channel and enter the matching code manually. Three failed SAS attempts terminate the session.
|
||||||
|
|
||||||
## Highlights in v4.8.9
|
## Highlights in v4.8.10
|
||||||
|
|
||||||
|
- New: users can configure their own STUN/TURN servers under "Advanced network settings" (header gear or the connection-creation screen). Input is allowlist-validated, optionally saved encrypted on-device, and a built-in "Test servers" check reports STUN/TURN reachability.
|
||||||
|
- Relay-only privacy mode moved into the advanced settings panel; the standalone start-screen toggle was removed.
|
||||||
|
|
||||||
|
Earlier in the v4.8 hardening line:
|
||||||
|
|
||||||
- Patched a high-severity XSS advisory in the DOMPurify dependency (the message sanitizer) by upgrading to a fixed release.
|
- Patched a high-severity XSS advisory in the DOMPurify dependency (the message sanitizer) by upgrading to a fixed release.
|
||||||
- Operator TURN credentials are no longer committed to the repository; use `config/ice-servers.example.js` as a template.
|
- Operator TURN credentials are no longer committed to the repository; use `config/ice-servers.example.js` as a template.
|
||||||
- The production logger no longer prints error context or info/debug output, only opaque error codes.
|
- The production logger no longer prints error context or info/debug output, only opaque error codes.
|
||||||
|
|
||||||
This patch release builds on the earlier hardening pass:
|
|
||||||
|
|
||||||
- Manual WebRTC setup preserves pending offer/answer state during slow out-of-band exchange.
|
- Manual WebRTC setup preserves pending offer/answer state during slow out-of-band exchange.
|
||||||
- TURN relay fallback can be configured through `config/ice-servers.js` for restrictive networks.
|
- TURN relay fallback can be configured through `config/ice-servers.js` for restrictive networks.
|
||||||
- ICE diagnostics identify mDNS-only candidate failures without exposing full peer IPs.
|
- ICE diagnostics identify mDNS-only candidate failures without exposing full peer IPs.
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ SecureBit.chat is intended for legitimate private communication, journalism, res
|
|||||||
|
|
||||||
## Current release
|
## Current release
|
||||||
|
|
||||||
- Product release: `v4.8.9`
|
- Product release: `v4.8.10`
|
||||||
- Protocol version: `4.1`
|
- Protocol version: `4.1`
|
||||||
- Last updated: May 17, 2026
|
- Last updated: May 17, 2026
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+11
-1
@@ -17481,7 +17481,7 @@ Right-click or Ctrl+click to disconnect`,
|
|||||||
React.createElement("p", {
|
React.createElement("p", {
|
||||||
key: "subtitle",
|
key: "subtitle",
|
||||||
className: "text-xs sm:text-sm text-muted hidden sm:block"
|
className: "text-xs sm:text-sm text-muted hidden sm:block"
|
||||||
}, "End-to-end freedom v4.8.9")
|
}, "End-to-end freedom v4.8.10")
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
// Status and Controls - Responsive
|
// Status and Controls - Responsive
|
||||||
@@ -17489,6 +17489,16 @@ Right-click or Ctrl+click to disconnect`,
|
|||||||
key: "status-section",
|
key: "status-section",
|
||||||
className: "flex items-center space-x-2 sm:space-x-3"
|
className: "flex items-center space-x-2 sm:space-x-3"
|
||||||
}, [
|
}, [
|
||||||
|
React.createElement("button", {
|
||||||
|
key: "network-settings",
|
||||||
|
type: "button",
|
||||||
|
onClick: () => window.dispatchEvent(new CustomEvent("securebit:open-network-settings")),
|
||||||
|
title: "Advanced network settings (STUN/TURN)",
|
||||||
|
"aria-label": "Advanced network settings",
|
||||||
|
className: "w-8 h-8 rounded-full flex items-center justify-center text-muted hover:text-primary hover:bg-white/5 transition-colors duration-200"
|
||||||
|
}, [
|
||||||
|
React.createElement("i", { key: "i", className: "fas fa-network-wired text-sm" })
|
||||||
|
]),
|
||||||
displaySecurityLevel && React.createElement("div", {
|
displaySecurityLevel && React.createElement("div", {
|
||||||
key: "security-level",
|
key: "security-level",
|
||||||
className: "hidden md:flex items-center space-x-2 cursor-pointer hover:opacity-80 transition-opacity duration-200",
|
className: "hidden md:flex items-center space-x-2 cursor-pointer hover:opacity-80 transition-opacity duration-200",
|
||||||
|
|||||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+32
-49
@@ -604,28 +604,6 @@ var EnhancedConnectionSetup = ({
|
|||||||
className: "text-secondary max-w-2xl mx-auto"
|
className: "text-secondary max-w-2xl mx-auto"
|
||||||
}, "Choose a connection method for a secure channel with ECDH encryption and Perfect Forward Secrecy.")
|
}, "Choose a connection method for a secure channel with ECDH encryption and Perfect Forward Secrecy.")
|
||||||
]),
|
]),
|
||||||
React.createElement("label", {
|
|
||||||
key: "privacy-mode",
|
|
||||||
className: "mb-6 mx-auto flex max-w-2xl items-start gap-3 rounded-xl border border-purple-500/20 bg-purple-500/10 p-4 text-left"
|
|
||||||
}, [
|
|
||||||
React.createElement("input", {
|
|
||||||
key: "input",
|
|
||||||
type: "checkbox",
|
|
||||||
checked: relayOnlyMode,
|
|
||||||
onChange: (event) => setRelayOnlyMode(event.target.checked),
|
|
||||||
className: "mt-1"
|
|
||||||
}),
|
|
||||||
React.createElement("span", { key: "copy" }, [
|
|
||||||
React.createElement("span", {
|
|
||||||
key: "title",
|
|
||||||
className: "block text-sm font-medium text-primary"
|
|
||||||
}, "Privacy mode: relay-only WebRTC"),
|
|
||||||
React.createElement("span", {
|
|
||||||
key: "desc",
|
|
||||||
className: "block text-sm text-secondary"
|
|
||||||
}, "Uses TURN relay-only when configured. Without TURN, direct WebRTC may expose IP addresses and relay-only connections cannot start.")
|
|
||||||
])
|
|
||||||
]),
|
|
||||||
React.createElement("div", {
|
React.createElement("div", {
|
||||||
key: "advanced-network",
|
key: "advanced-network",
|
||||||
className: "mb-6 mx-auto max-w-2xl flex flex-wrap items-center justify-between gap-3"
|
className: "mb-6 mx-auto max-w-2xl flex flex-wrap items-center justify-between gap-3"
|
||||||
@@ -633,31 +611,17 @@ var EnhancedConnectionSetup = ({
|
|||||||
React.createElement("span", {
|
React.createElement("span", {
|
||||||
key: "status",
|
key: "status",
|
||||||
className: "text-sm text-secondary"
|
className: "text-sm text-secondary"
|
||||||
}, Array.isArray(customIceServers) && customIceServers.length ? `Using ${customIceServers.length} custom ICE server(s)` : "Using public ICE servers"),
|
}, "STUN/TURN servers"),
|
||||||
React.createElement("button", {
|
React.createElement("button", {
|
||||||
key: "btn",
|
key: "btn",
|
||||||
type: "button",
|
type: "button",
|
||||||
onClick: () => setShowIceSettings(true),
|
onClick: () => window.dispatchEvent(new CustomEvent("securebit:open-network-settings")),
|
||||||
className: "px-3 py-2 text-sm rounded-lg border border-purple-500/30 text-primary"
|
className: "px-3 py-2 text-sm rounded-lg border border-purple-500/30 text-primary"
|
||||||
}, [
|
}, [
|
||||||
React.createElement("i", { key: "i", className: "fas fa-network-wired mr-2" }),
|
React.createElement("i", { key: "i", className: "fas fa-network-wired mr-2" }),
|
||||||
"Advanced network settings"
|
"Advanced network settings"
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
typeof window !== "undefined" && window.IceServerSettings ? React.createElement(window.IceServerSettings, {
|
|
||||||
key: "ice-settings-modal",
|
|
||||||
isOpen: showIceSettings,
|
|
||||||
onClose: () => setShowIceSettings(false),
|
|
||||||
initial: {
|
|
||||||
useCustom: Array.isArray(customIceServers) && customIceServers.length > 0,
|
|
||||||
serversText: iceServersText,
|
|
||||||
privacyMode: relayOnlyMode ? "relay-only" : "standard",
|
|
||||||
persisted: iceSettingsPersisted
|
|
||||||
},
|
|
||||||
hasSaved: iceSettingsPersisted,
|
|
||||||
onApply: handleApplyIceSettings,
|
|
||||||
onForget: handleForgetIceSettings
|
|
||||||
}) : null,
|
|
||||||
React.createElement("div", {
|
React.createElement("div", {
|
||||||
key: "options",
|
key: "options",
|
||||||
className: "flex flex-col md:flex-row items-center justify-center gap-6 max-w-3xl mx-auto"
|
className: "flex flex-col md:flex-row items-center justify-center gap-6 max-w-3xl mx-auto"
|
||||||
@@ -1633,10 +1597,10 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const [customIceServers2, setCustomIceServers] = React.useState(null);
|
const [customIceServers, setCustomIceServers] = React.useState(null);
|
||||||
const [iceServersText2, setIceServersText] = React.useState("");
|
const [iceServersText, setIceServersText] = React.useState("");
|
||||||
const [iceSettingsPersisted2, setIceSettingsPersisted] = React.useState(false);
|
const [iceSettingsPersisted, setIceSettingsPersisted] = React.useState(false);
|
||||||
const [showIceSettings2, setShowIceSettings2] = React.useState(false);
|
const [showIceSettings, setShowIceSettings] = React.useState(false);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
loadIceSettings().then((saved) => {
|
loadIceSettings().then((saved) => {
|
||||||
@@ -1655,23 +1619,28 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
const handleApplyIceSettings2 = React.useCallback((next, persist) => {
|
React.useEffect(() => {
|
||||||
|
const open = () => setShowIceSettings(true);
|
||||||
|
window.addEventListener("securebit:open-network-settings", open);
|
||||||
|
return () => window.removeEventListener("securebit:open-network-settings", open);
|
||||||
|
}, []);
|
||||||
|
const handleApplyIceSettings = React.useCallback((next, persist) => {
|
||||||
const servers = next.useCustom && Array.isArray(next.servers) ? next.servers : null;
|
const servers = next.useCustom && Array.isArray(next.servers) ? next.servers : null;
|
||||||
setCustomIceServers(servers && servers.length ? servers : null);
|
setCustomIceServers(servers && servers.length ? servers : null);
|
||||||
setIceServersText(next.serversText || "");
|
setIceServersText(next.serversText || "");
|
||||||
setRelayOnlyMode(next.privacyMode === "relay-only");
|
setRelayOnlyMode(next.privacyMode === "relay-only");
|
||||||
setShowIceSettings2(false);
|
setShowIceSettings(false);
|
||||||
if (persist) {
|
if (persist) {
|
||||||
setIceSettingsPersisted(true);
|
setIceSettingsPersisted(true);
|
||||||
saveIceSettings({ servers: servers || [], privacyMode: next.privacyMode }).catch(() => {
|
saveIceSettings({ servers: servers || [], privacyMode: next.privacyMode }).catch(() => {
|
||||||
});
|
});
|
||||||
} else if (iceSettingsPersisted2) {
|
} else if (iceSettingsPersisted) {
|
||||||
setIceSettingsPersisted(false);
|
setIceSettingsPersisted(false);
|
||||||
clearIceSettings().catch(() => {
|
clearIceSettings().catch(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [iceSettingsPersisted2]);
|
}, [iceSettingsPersisted]);
|
||||||
const handleForgetIceSettings2 = React.useCallback(async () => {
|
const handleForgetIceSettings = React.useCallback(async () => {
|
||||||
await clearIceSettings().catch(() => {
|
await clearIceSettings().catch(() => {
|
||||||
});
|
});
|
||||||
setIceSettingsPersisted(false);
|
setIceSettingsPersisted(false);
|
||||||
@@ -2004,7 +1973,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
webrtc: {
|
webrtc: {
|
||||||
relayOnly: relayOnlyMode,
|
relayOnly: relayOnlyMode,
|
||||||
// Priority: user's custom servers > operator override > built-in defaults.
|
// Priority: user's custom servers > operator override > built-in defaults.
|
||||||
iceServers: Array.isArray(customIceServers2) && customIceServers2.length ? customIceServers2 : Array.isArray(window.SECUREBIT_ICE_SERVERS) ? window.SECUREBIT_ICE_SERVERS : void 0
|
iceServers: Array.isArray(customIceServers) && customIceServers.length ? customIceServers : Array.isArray(window.SECUREBIT_ICE_SERVERS) ? window.SECUREBIT_ICE_SERVERS : void 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -2018,7 +1987,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleMessage(" SecureBit.chat Enhanced Security Edition v4.8.9 - ECDH + DTLS + SAS initialized. Ready to establish a secure connection with ECDH key exchange, DTLS fingerprint verification, and SAS authentication to prevent MITM attacks.", "system");
|
handleMessage(" SecureBit.chat Enhanced Security Edition v4.8.10 - ECDH + DTLS + SAS initialized. Ready to establish a secure connection with ECDH key exchange, DTLS fingerprint verification, and SAS authentication to prevent MITM attacks.", "system");
|
||||||
const handleBeforeUnload = (event) => {
|
const handleBeforeUnload = (event) => {
|
||||||
if (event.type === "beforeunload" && !isTabSwitching) {
|
if (event.type === "beforeunload" && !isTabSwitching) {
|
||||||
if (webrtcManagerRef.current && webrtcManagerRef.current.isConnected()) {
|
if (webrtcManagerRef.current && webrtcManagerRef.current.isConnected()) {
|
||||||
@@ -3434,6 +3403,20 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
return React.createElement("div", {
|
return React.createElement("div", {
|
||||||
className: "minimal-bg min-h-screen"
|
className: "minimal-bg min-h-screen"
|
||||||
}, [
|
}, [
|
||||||
|
typeof window !== "undefined" && window.IceServerSettings ? React.createElement(window.IceServerSettings, {
|
||||||
|
key: "ice-settings-modal",
|
||||||
|
isOpen: showIceSettings,
|
||||||
|
onClose: () => setShowIceSettings(false),
|
||||||
|
initial: {
|
||||||
|
useCustom: Array.isArray(customIceServers) && customIceServers.length > 0,
|
||||||
|
serversText: iceServersText,
|
||||||
|
privacyMode: relayOnlyMode ? "relay-only" : "standard",
|
||||||
|
persisted: iceSettingsPersisted
|
||||||
|
},
|
||||||
|
hasSaved: iceSettingsPersisted,
|
||||||
|
onApply: handleApplyIceSettings,
|
||||||
|
onForget: handleForgetIceSettings
|
||||||
|
}) : null,
|
||||||
window.EnhancedMinimalHeader && React.createElement(window.EnhancedMinimalHeader, {
|
window.EnhancedMinimalHeader && React.createElement(window.EnhancedMinimalHeader, {
|
||||||
key: "header",
|
key: "header",
|
||||||
status: connectionStatus,
|
status: connectionStatus,
|
||||||
|
|||||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
+5
-5
@@ -113,7 +113,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- GitHub Pages SEO -->
|
<!-- GitHub Pages SEO -->
|
||||||
<meta name="description" content="SecureBit.chat v4.8.9 — P2P messenger with ECDH + DTLS + SAS security and 18-layer military-grade cryptography">
|
<meta name="description" content="SecureBit.chat v4.8.10 — P2P messenger with ECDH + DTLS + SAS security and 18-layer military-grade cryptography">
|
||||||
<meta name="keywords" content="P2P messenger, ECDH, DTLS, SAS, encryption, WebRTC, privacy, ASN.1 validation, military-grade security, 18-layer defense, MITM protection, PFS">
|
<meta name="keywords" content="P2P messenger, ECDH, DTLS, SAS, encryption, WebRTC, privacy, ASN.1 validation, military-grade security, 18-layer defense, MITM protection, PFS">
|
||||||
<meta name="author" content="Volodymyr">
|
<meta name="author" content="Volodymyr">
|
||||||
<link rel="canonical" href="https://github.com/SecureBitChat/securebit-chat/">
|
<link rel="canonical" href="https://github.com/SecureBitChat/securebit-chat/">
|
||||||
@@ -148,13 +148,13 @@
|
|||||||
<!-- Update Manager - система принудительного обновления -->
|
<!-- Update Manager - система принудительного обновления -->
|
||||||
<script src="src/utils/updateManager.js"></script>
|
<script src="src/utils/updateManager.js"></script>
|
||||||
<script type="module" src="src/components/UpdateChecker.jsx"></script>
|
<script type="module" src="src/components/UpdateChecker.jsx"></script>
|
||||||
<script type="module" src="dist/qr-local.js?v=1781552284668"></script>
|
<script type="module" src="dist/qr-local.js?v=1781553880881"></script>
|
||||||
<script type="module" src="src/components/QRScanner.js?v=1781552284668"></script>
|
<script type="module" src="src/components/QRScanner.js?v=1781553880881"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="dist/app-boot.js?v=1781552284668"></script>
|
<script type="module" src="dist/app-boot.js?v=1781553880881"></script>
|
||||||
<script type="module" src="dist/app.js?v=1781552284668"></script>
|
<script type="module" src="dist/app.js?v=1781553880881"></script>
|
||||||
|
|
||||||
<script src="src/scripts/pwa-register.js"></script>
|
<script src="src/scripts/pwa-register.js"></script>
|
||||||
<script src="./src/pwa/install-prompt.js" type="module"></script>
|
<script src="./src/pwa/install-prompt.js" type="module"></script>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "SecureBit.chat v4.8.9 - ECDH + DTLS + SAS",
|
"name": "SecureBit.chat v4.8.10 - ECDH + DTLS + SAS",
|
||||||
"short_name": "SecureBit",
|
"short_name": "SecureBit",
|
||||||
"description": "P2P messenger with ECDH + DTLS + SAS security, military-grade cryptography and Lightning Network payments",
|
"description": "P2P messenger with ECDH + DTLS + SAS security, military-grade cryptography and Lightning Network payments",
|
||||||
"start_url": "./",
|
"start_url": "./",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"version": "1781552284668",
|
"version": "1781553880881",
|
||||||
"buildVersion": "1781552284668",
|
"buildVersion": "1781553880881",
|
||||||
"appVersion": "4.8.9",
|
"appVersion": "4.8.10",
|
||||||
"buildTime": "2026-06-15T19:38:04.713Z",
|
"buildTime": "2026-06-15T20:04:40.924Z",
|
||||||
"buildId": "1781552284668-366f080",
|
"buildId": "1781553880881-7f2ecce",
|
||||||
"gitHash": "366f080",
|
"gitHash": "7f2ecce",
|
||||||
"generated": true,
|
"generated": true,
|
||||||
"generatedAt": "2026-06-15T19:38:04.715Z"
|
"generatedAt": "2026-06-15T20:04:40.926Z"
|
||||||
}
|
}
|
||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "securebit-chat",
|
"name": "securebit-chat",
|
||||||
"version": "4.8.9",
|
"version": "4.8.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "securebit-chat",
|
"name": "securebit-chat",
|
||||||
"version": "4.8.9",
|
"version": "4.8.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "1.5.1",
|
"base64-js": "1.5.1",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "securebit-chat",
|
"name": "securebit-chat",
|
||||||
"version": "4.8.9",
|
"version": "4.8.10",
|
||||||
"description": "Secure P2P Communication Application with End-to-End Encryption",
|
"description": "Secure P2P Communication Application with End-to-End Encryption",
|
||||||
"main": "index.html",
|
"main": "index.html",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+26
-43
@@ -509,28 +509,6 @@ import { loadIceSettings, saveIceSettings, clearIceSettings } from './network/ic
|
|||||||
className: "text-secondary max-w-2xl mx-auto"
|
className: "text-secondary max-w-2xl mx-auto"
|
||||||
}, "Choose a connection method for a secure channel with ECDH encryption and Perfect Forward Secrecy.")
|
}, "Choose a connection method for a secure channel with ECDH encryption and Perfect Forward Secrecy.")
|
||||||
]),
|
]),
|
||||||
React.createElement('label', {
|
|
||||||
key: 'privacy-mode',
|
|
||||||
className: "mb-6 mx-auto flex max-w-2xl items-start gap-3 rounded-xl border border-purple-500/20 bg-purple-500/10 p-4 text-left"
|
|
||||||
}, [
|
|
||||||
React.createElement('input', {
|
|
||||||
key: 'input',
|
|
||||||
type: 'checkbox',
|
|
||||||
checked: relayOnlyMode,
|
|
||||||
onChange: (event) => setRelayOnlyMode(event.target.checked),
|
|
||||||
className: "mt-1"
|
|
||||||
}),
|
|
||||||
React.createElement('span', { key: 'copy' }, [
|
|
||||||
React.createElement('span', {
|
|
||||||
key: 'title',
|
|
||||||
className: "block text-sm font-medium text-primary"
|
|
||||||
}, 'Privacy mode: relay-only WebRTC'),
|
|
||||||
React.createElement('span', {
|
|
||||||
key: 'desc',
|
|
||||||
className: "block text-sm text-secondary"
|
|
||||||
}, 'Uses TURN relay-only when configured. Without TURN, direct WebRTC may expose IP addresses and relay-only connections cannot start.')
|
|
||||||
])
|
|
||||||
]),
|
|
||||||
|
|
||||||
React.createElement('div', {
|
React.createElement('div', {
|
||||||
key: 'advanced-network',
|
key: 'advanced-network',
|
||||||
@@ -539,33 +517,17 @@ import { loadIceSettings, saveIceSettings, clearIceSettings } from './network/ic
|
|||||||
React.createElement('span', {
|
React.createElement('span', {
|
||||||
key: 'status',
|
key: 'status',
|
||||||
className: "text-sm text-secondary"
|
className: "text-sm text-secondary"
|
||||||
}, (Array.isArray(customIceServers) && customIceServers.length)
|
}, 'STUN/TURN servers'),
|
||||||
? `Using ${customIceServers.length} custom ICE server(s)`
|
|
||||||
: 'Using public ICE servers'),
|
|
||||||
React.createElement('button', {
|
React.createElement('button', {
|
||||||
key: 'btn',
|
key: 'btn',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
onClick: () => setShowIceSettings(true),
|
onClick: () => window.dispatchEvent(new CustomEvent('securebit:open-network-settings')),
|
||||||
className: "px-3 py-2 text-sm rounded-lg border border-purple-500/30 text-primary"
|
className: "px-3 py-2 text-sm rounded-lg border border-purple-500/30 text-primary"
|
||||||
}, [
|
}, [
|
||||||
React.createElement('i', { key: 'i', className: 'fas fa-network-wired mr-2' }),
|
React.createElement('i', { key: 'i', className: 'fas fa-network-wired mr-2' }),
|
||||||
'Advanced network settings'
|
'Advanced network settings'
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
(typeof window !== 'undefined' && window.IceServerSettings) ? React.createElement(window.IceServerSettings, {
|
|
||||||
key: 'ice-settings-modal',
|
|
||||||
isOpen: showIceSettings,
|
|
||||||
onClose: () => setShowIceSettings(false),
|
|
||||||
initial: {
|
|
||||||
useCustom: Array.isArray(customIceServers) && customIceServers.length > 0,
|
|
||||||
serversText: iceServersText,
|
|
||||||
privacyMode: relayOnlyMode ? 'relay-only' : 'standard',
|
|
||||||
persisted: iceSettingsPersisted
|
|
||||||
},
|
|
||||||
hasSaved: iceSettingsPersisted,
|
|
||||||
onApply: handleApplyIceSettings,
|
|
||||||
onForget: handleForgetIceSettings
|
|
||||||
}) : null,
|
|
||||||
|
|
||||||
React.createElement('div', {
|
React.createElement('div', {
|
||||||
key: 'options',
|
key: 'options',
|
||||||
@@ -1620,6 +1582,13 @@ import { loadIceSettings, saveIceSettings, clearIceSettings } from './network/ic
|
|||||||
return () => { cancelled = true; };
|
return () => { cancelled = true; };
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Global entry point: the header gear dispatches this event.
|
||||||
|
React.useEffect(() => {
|
||||||
|
const open = () => setShowIceSettings(true);
|
||||||
|
window.addEventListener('securebit:open-network-settings', open);
|
||||||
|
return () => window.removeEventListener('securebit:open-network-settings', open);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleApplyIceSettings = React.useCallback((next, persist) => {
|
const handleApplyIceSettings = React.useCallback((next, persist) => {
|
||||||
const servers = next.useCustom && Array.isArray(next.servers) ? next.servers : null;
|
const servers = next.useCustom && Array.isArray(next.servers) ? next.servers : null;
|
||||||
setCustomIceServers(servers && servers.length ? servers : null);
|
setCustomIceServers(servers && servers.length ? servers : null);
|
||||||
@@ -2102,7 +2071,7 @@ import { loadIceSettings, saveIceSettings, clearIceSettings } from './network/ic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMessage(' SecureBit.chat Enhanced Security Edition v4.8.9 - ECDH + DTLS + SAS initialized. Ready to establish a secure connection with ECDH key exchange, DTLS fingerprint verification, and SAS authentication to prevent MITM attacks.', 'system');
|
handleMessage(' SecureBit.chat Enhanced Security Edition v4.8.10 - ECDH + DTLS + SAS initialized. Ready to establish a secure connection with ECDH key exchange, DTLS fingerprint verification, and SAS authentication to prevent MITM attacks.', 'system');
|
||||||
|
|
||||||
const handleBeforeUnload = (event) => {
|
const handleBeforeUnload = (event) => {
|
||||||
if (event.type === 'beforeunload' && !isTabSwitching) {
|
if (event.type === 'beforeunload' && !isTabSwitching) {
|
||||||
@@ -3791,9 +3760,23 @@ import { loadIceSettings, saveIceSettings, clearIceSettings } from './network/ic
|
|||||||
}
|
}
|
||||||
}, [showQRScannerModal]);
|
}, [showQRScannerModal]);
|
||||||
|
|
||||||
return React.createElement('div', {
|
return React.createElement('div', {
|
||||||
className: "minimal-bg min-h-screen"
|
className: "minimal-bg min-h-screen"
|
||||||
}, [
|
}, [
|
||||||
|
(typeof window !== 'undefined' && window.IceServerSettings) ? React.createElement(window.IceServerSettings, {
|
||||||
|
key: 'ice-settings-modal',
|
||||||
|
isOpen: showIceSettings,
|
||||||
|
onClose: () => setShowIceSettings(false),
|
||||||
|
initial: {
|
||||||
|
useCustom: Array.isArray(customIceServers) && customIceServers.length > 0,
|
||||||
|
serversText: iceServersText,
|
||||||
|
privacyMode: relayOnlyMode ? 'relay-only' : 'standard',
|
||||||
|
persisted: iceSettingsPersisted
|
||||||
|
},
|
||||||
|
hasSaved: iceSettingsPersisted,
|
||||||
|
onApply: handleApplyIceSettings,
|
||||||
|
onForget: handleForgetIceSettings
|
||||||
|
}) : null,
|
||||||
window.EnhancedMinimalHeader && React.createElement(window.EnhancedMinimalHeader, {
|
window.EnhancedMinimalHeader && React.createElement(window.EnhancedMinimalHeader, {
|
||||||
key: 'header',
|
key: 'header',
|
||||||
status: connectionStatus,
|
status: connectionStatus,
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ const EnhancedMinimalHeader = ({
|
|||||||
React.createElement('p', {
|
React.createElement('p', {
|
||||||
key: 'subtitle',
|
key: 'subtitle',
|
||||||
className: 'text-xs sm:text-sm text-muted hidden sm:block'
|
className: 'text-xs sm:text-sm text-muted hidden sm:block'
|
||||||
}, 'End-to-end freedom v4.8.9')
|
}, 'End-to-end freedom v4.8.10')
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@@ -549,6 +549,17 @@ const EnhancedMinimalHeader = ({
|
|||||||
className: 'flex items-center space-x-2 sm:space-x-3'
|
className: 'flex items-center space-x-2 sm:space-x-3'
|
||||||
}, [
|
}, [
|
||||||
|
|
||||||
|
React.createElement('button', {
|
||||||
|
key: 'network-settings',
|
||||||
|
type: 'button',
|
||||||
|
onClick: () => window.dispatchEvent(new CustomEvent('securebit:open-network-settings')),
|
||||||
|
title: 'Advanced network settings (STUN/TURN)',
|
||||||
|
'aria-label': 'Advanced network settings',
|
||||||
|
className: 'w-8 h-8 rounded-full flex items-center justify-center text-muted hover:text-primary hover:bg-white/5 transition-colors duration-200'
|
||||||
|
}, [
|
||||||
|
React.createElement('i', { key: 'i', className: 'fas fa-network-wired text-sm' })
|
||||||
|
]),
|
||||||
|
|
||||||
displaySecurityLevel && React.createElement('div', {
|
displaySecurityLevel && React.createElement('div', {
|
||||||
key: 'security-level',
|
key: 'security-level',
|
||||||
className: 'hidden md:flex items-center space-x-2 cursor-pointer hover:opacity-80 transition-opacity duration-200',
|
className: 'hidden md:flex items-center space-x-2 cursor-pointer hover:opacity-80 transition-opacity duration-200',
|
||||||
|
|||||||
Reference in New Issue
Block a user