@bivy/bivy 0.10.1-staging.331 → 0.10.1-staging.332
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runtime/oauth/oauth-node-open.js +30 -0
- package/dist/server.js +30 -2
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (c) 2026 Petter André Sjulstad
|
|
3
|
+
import { getModelOAuthProvider } from "./model-oauth-providers.js";
|
|
4
|
+
/**
|
|
5
|
+
* Open only the provider authorization URL generated for an active ceremony.
|
|
6
|
+
* The URL is checked against Bivy's owned provider registry before reaching the
|
|
7
|
+
* injected desktop opener, so this can never become an arbitrary remote-URL API.
|
|
8
|
+
*/
|
|
9
|
+
export function openOAuthLoginOnNode(login, opener) {
|
|
10
|
+
if (!login?.authUrl || login.status !== "waiting")
|
|
11
|
+
return { opened: false, error: "Login is no longer waiting for authorization." };
|
|
12
|
+
const provider = getModelOAuthProvider(login.provider);
|
|
13
|
+
if (!provider?.authorizeUrl)
|
|
14
|
+
return { opened: false, error: "Provider does not use a browser authorization page." };
|
|
15
|
+
let actual;
|
|
16
|
+
let expected;
|
|
17
|
+
try {
|
|
18
|
+
actual = new URL(login.authUrl);
|
|
19
|
+
expected = new URL(provider.authorizeUrl);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { opened: false, error: "Authorization URL is invalid." };
|
|
23
|
+
}
|
|
24
|
+
if (actual.protocol !== "https:" || actual.origin !== expected.origin || actual.pathname !== expected.pathname) {
|
|
25
|
+
return { opened: false, error: "Authorization URL did not match the provider." };
|
|
26
|
+
}
|
|
27
|
+
return opener(actual.toString())
|
|
28
|
+
? { opened: true }
|
|
29
|
+
: { opened: false, error: "This machine cannot open a graphical browser." };
|
|
30
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -52,6 +52,8 @@ import { execEphemeralRequest } from "./ephemeral-exec.js";
|
|
|
52
52
|
import { ApprovalManager } from "./approval.js";
|
|
53
53
|
import { QuestionManager, validQuestions, isAskUserQuestionTool, formatQuestionResult } from "./question.js";
|
|
54
54
|
import { NodeIdentity } from "./identity.js";
|
|
55
|
+
import { canOpenBrowser, openBrowser } from "./browser-open.js";
|
|
56
|
+
import { openOAuthLoginOnNode } from "./runtime/oauth/oauth-node-open.js";
|
|
55
57
|
import { collectNodeStats } from "./node-stats.js";
|
|
56
58
|
import { SessionEventCoalescer } from "./session-event-coalescer.js";
|
|
57
59
|
import { authMiddleware, resolveAuth, isAuthorized, requestOriginAllowed } from "./auth.js";
|
|
@@ -2883,6 +2885,8 @@ const RELAY_COMMANDS = {
|
|
|
2883
2885
|
instructions: state.instructions,
|
|
2884
2886
|
deviceCode: state.deviceCode,
|
|
2885
2887
|
usesCallbackServer: state.usesCallbackServer,
|
|
2888
|
+
canOpenOnNode: canOpenBrowser(),
|
|
2889
|
+
nodeName: identity.name,
|
|
2886
2890
|
error: state.error,
|
|
2887
2891
|
});
|
|
2888
2892
|
}
|
|
@@ -2890,6 +2894,21 @@ const RELAY_COMMANDS = {
|
|
|
2890
2894
|
relay?.sendEvent({ type: "session.error", error: error instanceof Error ? error.message : String(error) });
|
|
2891
2895
|
}
|
|
2892
2896
|
},
|
|
2897
|
+
// Open only the authorization URL generated inside this active ceremony. The
|
|
2898
|
+
// remote client never supplies an arbitrary URL, so this cannot become a
|
|
2899
|
+
// general remote-browser-launch primitive.
|
|
2900
|
+
"provider.oauth.open_on_node"(msg, ctx) {
|
|
2901
|
+
const requestId = String(msg.requestId ?? "");
|
|
2902
|
+
const state = oauthLogins.get(String(msg.id ?? ""));
|
|
2903
|
+
if (state?.openedOnNode) {
|
|
2904
|
+
ctx.reply({ type: "provider.oauth.open_on_node.result", requestId, opened: true, alreadyOpened: true });
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
const result = openOAuthLoginOnNode(state, openBrowser);
|
|
2908
|
+
if (result.opened && state)
|
|
2909
|
+
state.openedOnNode = true;
|
|
2910
|
+
ctx.reply({ type: "provider.oauth.open_on_node.result", requestId, ...result });
|
|
2911
|
+
},
|
|
2893
2912
|
// Paste-back step for providers that return a redirect URL/code instead of a
|
|
2894
2913
|
// pollable device code.
|
|
2895
2914
|
"provider.oauth.code"(msg) {
|
|
@@ -9492,13 +9511,22 @@ app.post("/api/auth/native-login", async (_req, res, next) => {
|
|
|
9492
9511
|
app.post("/api/auth/oauth/start", async (req, res, next) => {
|
|
9493
9512
|
try {
|
|
9494
9513
|
const provider = String(req.body?.provider ?? "openai-codex").trim();
|
|
9495
|
-
const state = await startOAuthLogin(provider);
|
|
9496
|
-
res.json({ ok: true, id: state.id, provider: state.provider, status: state.status, authUrl: state.authUrl, instructions: state.instructions, deviceCode: state.deviceCode, usesCallbackServer: state.usesCallbackServer, error: state.error });
|
|
9514
|
+
const state = await startOAuthLogin(provider, String(req.body?.label ?? "default"));
|
|
9515
|
+
res.json({ ok: true, id: state.id, provider: state.provider, status: state.status, authUrl: state.authUrl, instructions: state.instructions, deviceCode: state.deviceCode, usesCallbackServer: state.usesCallbackServer, canOpenOnNode: canOpenBrowser(), nodeName: identity.name, error: state.error });
|
|
9497
9516
|
}
|
|
9498
9517
|
catch (error) {
|
|
9499
9518
|
next(error);
|
|
9500
9519
|
}
|
|
9501
9520
|
});
|
|
9521
|
+
app.post("/api/auth/oauth/:id/open-on-node", (req, res) => {
|
|
9522
|
+
const state = oauthLogins.get(req.params.id);
|
|
9523
|
+
if (state?.openedOnNode)
|
|
9524
|
+
return res.json({ opened: true, alreadyOpened: true });
|
|
9525
|
+
const result = openOAuthLoginOnNode(state, openBrowser);
|
|
9526
|
+
if (result.opened && state)
|
|
9527
|
+
state.openedOnNode = true;
|
|
9528
|
+
res.json(result);
|
|
9529
|
+
});
|
|
9502
9530
|
app.post("/api/auth/oauth/:id/manual-code", (req, res) => {
|
|
9503
9531
|
const state = oauthLogins.get(req.params.id);
|
|
9504
9532
|
if (!state)
|
package/package.json
CHANGED