Picks up @Timtech4u's PR #33, which has been waiting since April. The design (CLI flag + threading through BrowserContext + http client) is theirs and is correct; this is a clean rewrite on top of current main because repeated rebase rounds had been reverting unrelated work that landed in the meantime. Issue #4 blocked all loopback / RFC1918 / link-local fetches to prevent SSRF. The only escape was OBSCURA_ALLOW_PRIVATE_NETWORK=1, which is process-wide and clunky in pipelines. Multiple users (@Timtech4u in the original PR, then @duartemvix and @necrogami in the comment thread) reported they cannot use obscura for development against http://localhost:N without it. Adds --allow-private-network as a global CLI flag, works on fetch, serve, and scrape. Threads through BrowserContext::with_storage_and_network and the http client's validate_url. CdpContext gets a new_full builder and obscura_cdp::start_with_full_serve_options entry point so 'obscura serve --allow-private-network' lets Puppeteer/Playwright navigate to localhost too. Default remains blocked. Backward compat: the env var still works (OR'd with the flag inside validate_url). All existing constructors and entry points unchanged. Verified end-to-end against a local http.server on 127.0.0.1: fetch and CDP Page.navigate both blocked by default, both succeed with the flag. Public URLs unaffected. Integration suite 28/28, full workspace cargo test all green.
This commit is contained in:
1 parent
1a1253118f
commit
e7bb0c676d
7 files changed
+140
-40
No files matched your search
@@ -80,7 +80,10 @@ pub async fn start_with_host_and_security(
|
||||
allow_file_access: bool,
|
||||
storage_dir: Option<std::path::PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
start_with_host_security_and_storage(port, host, proxy, stealth, user_agent, allow_file_access, storage_dir).await
|
||||
start_with_full_serve_options(
|
||||
port, host, proxy, stealth, user_agent, allow_file_access, storage_dir, false,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn start_with_host_security_and_storage(
|
||||
@@ -91,6 +94,25 @@ pub async fn start_with_host_security_and_storage(
|
||||
user_agent: Option<String>,
|
||||
allow_file_access: bool,
|
||||
storage_dir: Option<std::path::PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
start_with_full_serve_options(
|
||||
port, host, proxy, stealth, user_agent, allow_file_access, storage_dir, false,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Full serve entry point that also accepts `allow_private_network` (issue
|
||||
/// #33). Older entry points default it to `false` so existing callers and
|
||||
/// public API consumers are unaffected.
|
||||
pub async fn start_with_full_serve_options(
|
||||
port: u16,
|
||||
host: &str,
|
||||
proxy: Option<String>,
|
||||
stealth: bool,
|
||||
user_agent: Option<String>,
|
||||
allow_file_access: bool,
|
||||
storage_dir: Option<std::path::PathBuf>,
|
||||
allow_private_network: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let ip: std::net::IpAddr = host
|
||||
.parse()
|
||||
@@ -162,6 +184,7 @@ pub async fn start_with_host_security_and_storage(
|
||||
|
||||
let _processor_handle = tokio::task::spawn_local(cdp_processor(
|
||||
msg_rx, proxy, stealth, user_agent, allow_file_access, storage_dir,
|
||||
allow_private_network,
|
||||
));
|
||||
|
||||
while let Some(stream) = ws_rx.recv().await {
|
||||
@@ -300,13 +323,16 @@ async fn cdp_processor(
|
||||
user_agent: Option<String>,
|
||||
allow_file_access: bool,
|
||||
storage_dir: Option<std::path::PathBuf>,
|
||||
allow_private_network: bool,
|
||||
) {
|
||||
let mut ctx = if storage_dir.is_some() {
|
||||
// Use storage-aware context creation with security settings
|
||||
CdpContext::new_with_storage(proxy, stealth, user_agent, storage_dir)
|
||||
} else {
|
||||
CdpContext::new_with_security(proxy, stealth, user_agent, allow_file_access)
|
||||
};
|
||||
let mut ctx = CdpContext::new_full(
|
||||
proxy,
|
||||
stealth,
|
||||
user_agent,
|
||||
storage_dir,
|
||||
allow_file_access,
|
||||
allow_private_network,
|
||||
);
|
||||
let (itx, irx) = mpsc::unbounded_channel::<obscura_js::ops::InterceptedRequest>();
|
||||
ctx.intercept_tx = Some(itx);
|
||||
let mut intercept_rx: Option<mpsc::UnboundedReceiver<obscura_js::ops::InterceptedRequest>> = Some(irx);
|
||||
|
||||
Reference in new issue
Block a user