fix(oauth): harden browser launch handling
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { getOAuthProviders, type OAuthDeviceCodeInfo } from "@earendil-works/pi-ai/oauth";
|
||||
import { Container, type Focusable, getKeybindings, Input, Spacer, Text, type TUI } from "@earendil-works/pi-tui";
|
||||
import { exec } from "child_process";
|
||||
import { openBrowser } from "../../../utils/open-browser.ts";
|
||||
import { theme } from "../theme/theme.ts";
|
||||
import { DynamicBorder } from "./dynamic-border.ts";
|
||||
import { keyHint } from "./keybinding-hints.ts";
|
||||
@@ -101,7 +101,7 @@ export class LoginDialogComponent extends Container implements Focusable {
|
||||
this.contentContainer.addChild(new Text(theme.fg("warning", instructions), 1, 0));
|
||||
}
|
||||
|
||||
this.openUrl(url);
|
||||
openBrowser(url);
|
||||
this.tui.requestRender();
|
||||
}
|
||||
|
||||
@@ -120,19 +120,10 @@ export class LoginDialogComponent extends Container implements Focusable {
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
this.contentContainer.addChild(new Text(theme.fg("warning", `Enter code: ${info.userCode}`), 1, 0));
|
||||
|
||||
this.openUrl(info.verificationUri);
|
||||
openBrowser(info.verificationUri);
|
||||
this.tui.requestRender();
|
||||
}
|
||||
|
||||
private openUrl(url: string): void {
|
||||
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
||||
try {
|
||||
exec(`${openCmd} "${url}"`, () => {});
|
||||
} catch {
|
||||
// Ignore browser launch failures. The URL remains visible for manual opening/copying.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show input for manual code/URL entry (for callback server providers)
|
||||
*/
|
||||
|
||||
24
packages/coding-agent/src/utils/open-browser.ts
Normal file
24
packages/coding-agent/src/utils/open-browser.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
/**
|
||||
* Open a URL or file in the platform browser/default handler.
|
||||
*
|
||||
* This intentionally never invokes a shell. On Windows, do not use
|
||||
* `cmd /c start`: cmd.exe re-parses metacharacters (&, |, ^, ...) before
|
||||
* `start` runs, which would make attacker-controlled URLs injectable.
|
||||
*/
|
||||
export function openBrowser(target: string): void {
|
||||
const [cmd, args]: [string, string[]] =
|
||||
process.platform === "darwin"
|
||||
? ["open", [target]]
|
||||
: process.platform === "win32"
|
||||
? ["rundll32", ["url.dll,FileProtocolHandler", target]]
|
||||
: ["xdg-open", [target]];
|
||||
|
||||
// spawn reports launcher failures (for example, missing xdg-open) via an
|
||||
// error event. Browser launch is best-effort: callers still present the target
|
||||
// to the user, so keep the launcher failure from becoming a process crash.
|
||||
spawn(cmd, args, { stdio: "ignore", detached: true })
|
||||
.on("error", () => {})
|
||||
.unref();
|
||||
}
|
||||
Reference in New Issue
Block a user