mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-19 22:01:43 +00:00
feat(inspector): add local network access support for HTTPS to HTTP connections
This commit is contained in:
parent
e984d07c28
commit
d1cbd20b83
4 changed files with 83 additions and 2 deletions
|
|
@ -341,6 +341,20 @@
|
||||||
color: var(--success);
|
color: var(--success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.banner.warning {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
background: rgba(255, 159, 10, 0.1);
|
||||||
|
border-left: 3px solid var(--warning);
|
||||||
|
color: var(--warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner.warning svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,14 @@ export default function App() {
|
||||||
};
|
};
|
||||||
let logged = false;
|
let logged = false;
|
||||||
|
|
||||||
|
// Add targetAddressSpace for local network access from HTTPS
|
||||||
|
const fetchInit = {
|
||||||
|
...init,
|
||||||
|
targetAddressSpace: "loopback"
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(input, init);
|
const response = await fetch(input, fetchInit);
|
||||||
logRequest({ ...entry, status: response.status });
|
logRequest({ ...entry, status: response.status });
|
||||||
logged = true;
|
logged = true;
|
||||||
return response;
|
return response;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Zap } from "lucide-react";
|
import { AlertTriangle, Zap } from "lucide-react";
|
||||||
|
import { isHttpsToHttpConnection, isLocalNetworkTarget } from "../lib/permissions";
|
||||||
|
|
||||||
const ConnectScreen = ({
|
const ConnectScreen = ({
|
||||||
endpoint,
|
endpoint,
|
||||||
|
|
@ -50,6 +51,18 @@ const ConnectScreen = ({
|
||||||
|
|
||||||
{connectError && <div className="banner error">{connectError}</div>}
|
{connectError && <div className="banner error">{connectError}</div>}
|
||||||
|
|
||||||
|
{isHttpsToHttpConnection(window.location.href, endpoint) &&
|
||||||
|
isLocalNetworkTarget(endpoint) && (
|
||||||
|
<div className="banner warning">
|
||||||
|
<AlertTriangle size={16} />
|
||||||
|
<span>
|
||||||
|
Connecting from HTTPS to a local HTTP server requires{" "}
|
||||||
|
<strong>local network access</strong> permission. Your browser may prompt you to
|
||||||
|
allow this connection.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<label className="field">
|
<label className="field">
|
||||||
<span className="label">Endpoint</span>
|
<span className="label">Endpoint</span>
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
48
frontend/packages/inspector/src/lib/permissions.ts
Normal file
48
frontend/packages/inspector/src/lib/permissions.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
export const askForLocalNetworkAccess = async (): Promise<boolean> => {
|
||||||
|
try {
|
||||||
|
const status = await navigator.permissions.query({
|
||||||
|
// @ts-expect-error - local-network-access is not in standard types
|
||||||
|
name: "local-network-access"
|
||||||
|
});
|
||||||
|
if (status.state === "granted") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (status.state === "denied") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If promptable, return true - browser will prompt on first request
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
// Permissions API not supported or permission not recognized - try anyway
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isHttpsToHttpConnection = (pageUrl: string, targetUrl: string): boolean => {
|
||||||
|
try {
|
||||||
|
const page = new URL(pageUrl);
|
||||||
|
const target = new URL(targetUrl);
|
||||||
|
return page.protocol === "https:" && target.protocol === "http:";
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isLocalNetworkTarget = (targetUrl: string): boolean => {
|
||||||
|
try {
|
||||||
|
const url = new URL(targetUrl);
|
||||||
|
const hostname = url.hostname.toLowerCase();
|
||||||
|
return (
|
||||||
|
hostname === "localhost" ||
|
||||||
|
hostname === "127.0.0.1" ||
|
||||||
|
hostname === "::1" ||
|
||||||
|
hostname.endsWith(".local") ||
|
||||||
|
// Private IPv4 ranges
|
||||||
|
/^10\./.test(hostname) ||
|
||||||
|
/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname) ||
|
||||||
|
/^192\.168\./.test(hostname)
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue