Skip to content

Commit

Permalink
[wrangler] fix: listen on loopback for wrangler dev port check and login
Browse files Browse the repository at this point in the history
The `wrangler dev` port availability check triggers a firewall prompt on
macOS while it briefly opens and closes listeners. The OAuth callback
server from `wrangler login` has the same issue.

Fix both cases by listening on the loopback address only by default.

Relates to cloudflare#4430
  • Loading branch information
Lekensteyn committed Jan 30, 2024
1 parent 749fa3c commit 0332176
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 9 deletions.
10 changes: 10 additions & 0 deletions .changeset/smart-owls-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"wrangler": patch
---

fix: listen on loopback for wrangler dev port check and login

Avoid listening on the wildcard address by default to reduce the attacker's
surface and avoid firewall prompts on macOS.

Relates to #4430.
15 changes: 10 additions & 5 deletions packages/wrangler/src/dev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -626,12 +626,16 @@ export async function startApiDev(args: StartDevOptions) {
};
}
/**
* Get an available TCP port number.
*
* Avoiding calling `getPort()` multiple times by memoizing the first result.
*/
function memoizeGetPort(defaultPort?: number) {
function memoizeGetPort(defaultPort: number, host: string) {
let portValue: number;
return async () => {
return portValue || (portValue = await getPort({ port: defaultPort }));
// Check a specific host to avoid probing all local addresses.
portValue = portValue ?? (await getPort({ port: defaultPort, host: host }));
return portValue;
};
}
/**
Expand Down Expand Up @@ -705,14 +709,15 @@ async function validateDevServerSettings(
);

const { zoneId, host, routes } = await getZoneIdHostAndRoutes(args, config);
const getLocalPort = memoizeGetPort(DEFAULT_LOCAL_PORT);
const getInspectorPort = memoizeGetPort(DEFAULT_INSPECTOR_PORT);
const initialIp = args.ip || config.dev.ip;
const getLocalPort = memoizeGetPort(DEFAULT_LOCAL_PORT, initialIp);
const getInspectorPort = memoizeGetPort(DEFAULT_INSPECTOR_PORT, "localhost");

// Our inspector proxy server will be binding to the result of
// `getInspectorPort`. If we attempted to bind workerd to the same inspector
// port, we'd get a port already in use error. Therefore, generate a new port
// for our runtime to bind its inspector service to.
const getRuntimeInspectorPort = memoizeGetPort();
const getRuntimeInspectorPort = memoizeGetPort(0, "localhost");

if (config.services && config.services.length > 0) {
logger.warn(
Expand Down
8 changes: 5 additions & 3 deletions packages/wrangler/src/dev/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ export async function startPreviewServer({
accessTokenRef,
});

await waitForPortToBeAvailable(port, {
const listenCheckIp = ip === "*" ? "0.0.0.0" : ip;
await waitForPortToBeAvailable(port, listenCheckIp, {
retryPeriod: 200,
timeout: 2000,
abortSignal: abortController.signal,
Expand Down Expand Up @@ -295,7 +296,7 @@ export function usePreviewServer({
return;
}

waitForPortToBeAvailable(port, {
waitForPortToBeAvailable(port, listenCheckIp, {
retryPeriod: 200,
timeout: 2000,
abortSignal: abortController.signal,
Expand Down Expand Up @@ -636,6 +637,7 @@ function createStreamHandler(
*/
export async function waitForPortToBeAvailable(
port: number,
host: string,
options: { retryPeriod: number; timeout: number; abortSignal: AbortSignal }
): Promise<void> {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -686,7 +688,7 @@ export async function waitForPortToBeAvailable(
doReject(err);
}
});
server.listen(port, () =>
server.listen(port, host, () =>
terminator
.terminate()
.then(doResolve, () =>
Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/src/user/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ export async function login(
}
});

server.listen(8976);
server.listen(8976, "localhost");
});
if (props?.browser) {
logger.log(`Opening a link in your default browser: ${urlToOpen}`);
Expand Down

0 comments on commit 0332176

Please sign in to comment.