Repository navigation
Conversation
`isLocalBridgeAddress` accepts `localhost` and `::1`, but the extension's `connect-src` only lists `127.0.0.1`. A pasted `ws://localhost:<port>` URL was therefore blocked by the extension's own CSP during the pre-flight; the fallback discovery then excluded that port and either found nothing or attached to another local instance. Rewrite the hostname of a local bridge URL to `127.0.0.1` before probing and connecting. The saved setting is left untouched, and the CSP stays at the current least-privilege value.
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are recorded for the manual loopback bridge connection fix.
No open issues 🎉
What changed in this PR
Fixes manual loopback bridge connections by routing probes and WebSocket connections through the extension’s CSP-allowed 127.0.0.1 origin.
Changes:
- Normalizes local bridge hostnames before probing and connecting, without changing saved settings or CSP.
- Adds regression tests for
localhostand IPv6 loopback addresses, verifying both connection URLs.
| File | Description |
|---|---|
extensions/dsh-browser/tests/background-bridge-lifecycle.spec.ts |
Tests manual loopback aliases against a simulated CSP restriction. |
extensions/dsh-browser/src/background/index.ts |
Adds loopback URL normalization and applies it before the manual connection preflight. |
Review effort: Max
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述 / Summary
Probe and connect a manually entered loopback bridge URL through
127.0.0.1— the only loopback origin the extension'sconnect-srcallows — instead of failing onlocalhost/::1aliases.动机 / Motivation
isLocalBridgeAddressacceptslocalhost,[::1], and::1as local bridge addresses (extensions/dsh-browser/src/background/index.ts), and the settings address field is free text. But the extension's own CSP lists only127.0.0.1:extensions/dsh-browser/manifest.json→connect-src ws://127.0.0.1:* http://127.0.0.1:* https://raw.githubusercontent.comextensions/dsh-browser/manifest.firefox.json→ sameChrome applies
content_security_policy.extension_pagesto the background service worker, andconnect-srcgovernsfetch()andWebSocket(https://developer.chrome.com/docs/extensions/reference/manifest/content-security-policy, https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src).So for a pasted
ws://localhost:3080/ext/bridge:probeBridge()fetcheshttp://localhost:3080/ext/bridge-config, which the extension's own CSP blocks before it reaches the host → the pre-flight reports "not reachable".startBridge()then falls back to one discovery pass, passing the failed URL asexcludeUrl;planDiscovery()excludes its port.dsh webprintslocalhost, so a manual paste is a realistic path.改动内容 / Changes
canonicalLoopbackUrl(): rewrite the hostname of a local bridge URL to127.0.0.1(port, path, and query preserved); remote URLs pass through untouched.startBridge()before the pre-flight and before the socket is opened. The saveddshSettings.bridgeUrlis not rewritten — the user's text stays as typed, matching the existing contract.connect-srcat127.0.0.1preserves the current least-privilege policy and still covers IPv6 loopback.测试 / Testing
it.eachcases forws://localhost:3080/ext/bridgeandws://[::1]:3080/ext/bridgeintests/background-bridge-lifecycle.spec.ts. The fetch mock rejects any non-127.0.0.1host (the CSP rule) and only port 3080 answers; the test asserts the probe goes tohttp://127.0.0.1:3080/ext/bridge-configand the WebSocket opens atws://127.0.0.1:3080/ext/bridge.expected [] to have a length of 1); with a second instance answering on 3081, the old flow attached tows://127.0.0.1:3081/ext/bridgeinstead of the requested 3080. After the fix, 2/2 pass.npx vitest run tests/background-bridge-lifecycle.spec.ts→ 21 passedpnpm test→ extension 77 files / 668 tests passed; bridge 18 files / 211 tests passednpx tsc -b --pretty false→ cleanpnpm run build→ cleanThis is a unit-level reproduction of the CSP-blocked pre-flight, not a real-browser E2E run (no browser harness in this environment). The CSP rule itself is taken from the Chrome extension CSP contract and from this repo's own
connect-src, which already whitelistshttps://raw.githubusercontent.comfor update fetches.影响范围 / Impact
127.0.0.1URLs behave exactly as before.Checklist
pnpm run build/bash -n scripts/install.sh等基础检查 / Passed build checks