Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/activate/__tests__/handleUri.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
const { mockShowWarningMessage } = vi.hoisted(() => ({
mockShowWarningMessage:
vi.fn<
(
message: string,
options: import("vscode").MessageOptions,
...items: string[]
) => Promise<string | undefined>
>(),
}))

vi.mock("vscode", () => ({
window: {
showInformationMessage: vi.fn(),
showWarningMessage: mockShowWarningMessage,
},
}))

Expand Down Expand Up @@ -53,11 +65,13 @@ const makeCallbackProvider = (callback = vi.fn()): ClineProvider =>
describe("handleUri", () => {
beforeEach(() => {
vi.clearAllMocks()
mockShowWarningMessage.mockResolvedValue(undefined)
mockGetVisibleInstance.mockReturnValue(mockVisibleProvider)
mockGetAllInstances.mockReturnValue([mockVisibleProvider])
})

it.each(["/openrouter", "/requesty"])("dispatches %s codes without losing literal plus signs", async (path) => {
mockShowWarningMessage.mockImplementation(async () => "Activate Requesty")
await handleUri(makeUri({ path, query: "code=a+b%2Bc&baseUrl=https%3A%2F%2Fexample.com" }))

if (path === "/openrouter") {
Expand All @@ -70,7 +84,47 @@ describe("handleUri", () => {
})

it("passes null when Requesty has no base URL", async () => {
mockShowWarningMessage.mockImplementation(async () => "Activate Requesty")
await handleUri(makeUri({ path: "/requesty", query: "code=test-code" }))
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
"Activate Requesty credentials from an external link?",
expect.objectContaining({ modal: true, detail: expect.stringContaining("https://router.requesty.ai/v1") }),
"Activate Requesty",
)
expect(mockVisibleProvider.handleRequestyCallback).toHaveBeenCalledWith("test-code", null)
})

it.each([undefined, "Cancel"])(
"does not apply an unsolicited Requesty callback when dismissed with %s",
async (choice) => {
mockShowWarningMessage.mockImplementation(async () => choice)
await handleUri(
makeUri({ path: "/requesty", query: "code=attacker-key&baseUrl=https://attacker.example/v1" }),
)
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
"Activate Requesty credentials from an external link?",
expect.objectContaining({
modal: true,
detail: expect.stringContaining("https://attacker.example/v1"),
}),
"Activate Requesty",
)
expect(mockVisibleProvider.handleRequestyCallback).not.toHaveBeenCalled()
},
)

it("waits for explicit approval before applying callback credentials", async () => {
let approve: (choice: string | undefined) => void = () => {}
mockShowWarningMessage.mockImplementation(
() =>
new Promise<string | undefined>((resolve) => {
approve = resolve
}),
)
const callback = handleUri(makeUri({ path: "/requesty", query: "code=test-code" }))
expect(mockVisibleProvider.handleRequestyCallback).not.toHaveBeenCalled()
approve("Activate Requesty")
await callback
expect(mockVisibleProvider.handleRequestyCallback).toHaveBeenCalledWith("test-code", null)
})

Expand Down
18 changes: 17 additions & 1 deletion src/activate/handleUri.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as vscode from "vscode"

import { toRequestyServiceUrl } from "../shared/utils/requesty"

import { getRouterUnavailableSignInMessage } from "../core/config/routerRemoval"
import { ClineProvider } from "../core/webview/ClineProvider"
import { handleAuthCallback as handleZooCodeAuthCallback, setZooCodeUserInfo } from "../services/zoo-code-auth"
Expand Down Expand Up @@ -51,7 +53,21 @@ export const handleUri = async (uri: vscode.Uri) => {
const code = query.get("code")
const baseUrl = query.get("baseUrl")
if (code) {
await visibleProvider.handleRequestyCallback(code, baseUrl)
// Deep links are untrusted. Require consent before installing credentials
// or redirecting an existing task's conversation to this destination.
const destination = toRequestyServiceUrl(baseUrl)
const approve = "Activate Requesty"
const choice = await vscode.window.showWarningMessage(
"Activate Requesty credentials from an external link?",
{
modal: true,
detail: `This will replace the active provider. Subsequent requests can send your conversation and workspace content to:\n${JSON.stringify(destination)}\n\nContinue only if you requested these credentials and trust this destination.`,
},
approve,
)
if (choice === approve) {
await visibleProvider.handleRequestyCallback(code, baseUrl)
}
}
break
}
Expand Down
Loading