opencode-codebuddy-external-auth 1.0.21 → 1.0.22
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/plugin.js +69 -12
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -9,7 +9,7 @@ const CONFIG = {
|
|
|
9
9
|
// IOA 版本使用 copilot.tencent.com 进行认证
|
|
10
10
|
serverUrl: "https://copilot.tencent.com",
|
|
11
11
|
// 真实对话 API 路径
|
|
12
|
-
chatCompletionsPath: "/v2/chat/completions",
|
|
12
|
+
chatCompletionsPath: "/v2/plugin/chat/completions",
|
|
13
13
|
// 平台标识
|
|
14
14
|
platform: "CLI",
|
|
15
15
|
appVersion: "2.37.20",
|
|
@@ -39,6 +39,35 @@ function generateUuid() {
|
|
|
39
39
|
}
|
|
40
40
|
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
41
41
|
}
|
|
42
|
+
function generateHexId(length) {
|
|
43
|
+
const bytes = Math.ceil(length / 2);
|
|
44
|
+
const buffer = new Uint8Array(bytes);
|
|
45
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
46
|
+
globalThis.crypto.getRandomValues(buffer);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
for (let i = 0; i < buffer.length; i += 1) {
|
|
50
|
+
buffer[i] = Math.floor(Math.random() * 256);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return Array.from(buffer)
|
|
54
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
55
|
+
.join("")
|
|
56
|
+
.slice(0, length);
|
|
57
|
+
}
|
|
58
|
+
function buildTraceHeaders() {
|
|
59
|
+
const traceId = generateHexId(32);
|
|
60
|
+
const spanId = generateHexId(16);
|
|
61
|
+
const parentSpanId = generateHexId(16);
|
|
62
|
+
const sampled = "1";
|
|
63
|
+
return {
|
|
64
|
+
"X-B3-TraceId": traceId,
|
|
65
|
+
"X-B3-ParentSpanId": parentSpanId,
|
|
66
|
+
"X-B3-SpanId": spanId,
|
|
67
|
+
"X-B3-Sampled": sampled,
|
|
68
|
+
b3: `${traceId}-${spanId}-${sampled}-${parentSpanId}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
42
71
|
function decodeJwtPayload(token) {
|
|
43
72
|
try {
|
|
44
73
|
const parts = token.split(".");
|
|
@@ -204,10 +233,25 @@ function pickFallbackModel(models) {
|
|
|
204
233
|
return "glm-4.7-ioa";
|
|
205
234
|
return models[0] || "";
|
|
206
235
|
}
|
|
236
|
+
function buildEnterpriseHeaders(accessToken) {
|
|
237
|
+
const tenantId = cachedTenantId || resolveTenantId(accessToken);
|
|
238
|
+
const enterpriseId = cachedEnterpriseId || resolveEnterpriseId(accessToken);
|
|
239
|
+
const resolvedTenantId = tenantId || enterpriseId;
|
|
240
|
+
if (tenantId)
|
|
241
|
+
cachedTenantId = tenantId;
|
|
242
|
+
if (enterpriseId)
|
|
243
|
+
cachedEnterpriseId = enterpriseId;
|
|
244
|
+
const headers = {};
|
|
245
|
+
if (resolvedTenantId)
|
|
246
|
+
headers["X-Tenant-Id"] = resolvedTenantId;
|
|
247
|
+
if (enterpriseId)
|
|
248
|
+
headers["X-Enterprise-Id"] = enterpriseId;
|
|
249
|
+
return headers;
|
|
250
|
+
}
|
|
207
251
|
async function buildAuthHeaders(accessToken) {
|
|
208
252
|
const payload = decodeJwtPayload(accessToken);
|
|
209
253
|
const roles = payload?.realm_access?.roles || payload?.resource_access?.account?.roles;
|
|
210
|
-
|
|
254
|
+
let tenantId = cachedTenantId || resolveTenantId(accessToken);
|
|
211
255
|
let enterpriseId = cachedEnterpriseId || resolveEnterpriseId(accessToken);
|
|
212
256
|
const userId = cachedUserId || resolveUserId(accessToken);
|
|
213
257
|
if (!enterpriseId) {
|
|
@@ -217,6 +261,9 @@ async function buildAuthHeaders(accessToken) {
|
|
|
217
261
|
cachedModelIds = config.models;
|
|
218
262
|
}
|
|
219
263
|
}
|
|
264
|
+
if (!tenantId && enterpriseId) {
|
|
265
|
+
tenantId = enterpriseId;
|
|
266
|
+
}
|
|
220
267
|
if (tenantId)
|
|
221
268
|
cachedTenantId = tenantId;
|
|
222
269
|
if (enterpriseId)
|
|
@@ -243,6 +290,8 @@ async function buildAuthHeaders(accessToken) {
|
|
|
243
290
|
const conversationId = generateUuid();
|
|
244
291
|
const messageId = generateUuid();
|
|
245
292
|
const requestId = messageId;
|
|
293
|
+
const traceHeaders = buildTraceHeaders();
|
|
294
|
+
const encodedUserId = userId ? encodeURIComponent(userId) : "";
|
|
246
295
|
const headers = {
|
|
247
296
|
"Accept": "application/json",
|
|
248
297
|
"Content-Type": "application/json",
|
|
@@ -259,13 +308,14 @@ async function buildAuthHeaders(accessToken) {
|
|
|
259
308
|
"X-Domain": CONFIG.domain,
|
|
260
309
|
"X-Product": CONFIG.product,
|
|
261
310
|
"User-Agent": `CLI/${CONFIG.appVersion} CodeBuddy/${CONFIG.appVersion}`,
|
|
311
|
+
...traceHeaders,
|
|
262
312
|
};
|
|
263
313
|
if (tenantId)
|
|
264
314
|
headers["X-Tenant-Id"] = tenantId;
|
|
265
315
|
if (enterpriseId)
|
|
266
316
|
headers["X-Enterprise-Id"] = enterpriseId;
|
|
267
|
-
if (
|
|
268
|
-
headers["X-User-Id"] =
|
|
317
|
+
if (encodedUserId)
|
|
318
|
+
headers["X-User-Id"] = encodedUserId;
|
|
269
319
|
return headers;
|
|
270
320
|
}
|
|
271
321
|
/**
|
|
@@ -503,7 +553,7 @@ async function executeViaAuthApi(openaiRequest, auth) {
|
|
|
503
553
|
};
|
|
504
554
|
let response = await doRequest(accessToken);
|
|
505
555
|
if ((response.status === 401 || response.status === 403) && auth.refresh) {
|
|
506
|
-
const refreshed = await refreshAccessToken(auth.refresh);
|
|
556
|
+
const refreshed = await refreshAccessToken(auth.refresh, accessToken);
|
|
507
557
|
if (refreshed?.accessToken) {
|
|
508
558
|
accessToken = refreshed.accessToken;
|
|
509
559
|
response = await doRequest(accessToken);
|
|
@@ -716,15 +766,22 @@ async function pollForToken(state, expiresAt, signal) {
|
|
|
716
766
|
/**
|
|
717
767
|
* Refresh the access token
|
|
718
768
|
*/
|
|
719
|
-
async function refreshAccessToken(refreshToken) {
|
|
769
|
+
async function refreshAccessToken(refreshToken, accessToken) {
|
|
720
770
|
try {
|
|
771
|
+
const traceHeaders = buildTraceHeaders();
|
|
772
|
+
const headers = {
|
|
773
|
+
"Content-Type": "application/json",
|
|
774
|
+
"Accept": "application/json",
|
|
775
|
+
"X-Refresh-Token": refreshToken,
|
|
776
|
+
...traceHeaders,
|
|
777
|
+
};
|
|
778
|
+
if (accessToken) {
|
|
779
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
780
|
+
Object.assign(headers, buildEnterpriseHeaders(accessToken));
|
|
781
|
+
}
|
|
721
782
|
const response = await fetch(`${CONFIG.serverUrl}/v2/plugin/auth/token/refresh`, {
|
|
722
783
|
method: "POST",
|
|
723
|
-
headers
|
|
724
|
-
"Content-Type": "application/json",
|
|
725
|
-
"Accept": "application/json",
|
|
726
|
-
"Authorization": `Bearer ${refreshToken}`,
|
|
727
|
-
},
|
|
784
|
+
headers,
|
|
728
785
|
});
|
|
729
786
|
if (!response.ok) {
|
|
730
787
|
console.warn(`[codebuddy-external] Token refresh failed: ${response.status}`);
|
|
@@ -766,7 +823,7 @@ const CodeBuddyExternalAuthPlugin = async (_input) => {
|
|
|
766
823
|
if (auth.type !== "oauth" || !auth.refresh) {
|
|
767
824
|
return null;
|
|
768
825
|
}
|
|
769
|
-
const tokenData = await refreshAccessToken(auth.refresh);
|
|
826
|
+
const tokenData = await refreshAccessToken(auth.refresh, auth.access);
|
|
770
827
|
if (!tokenData) {
|
|
771
828
|
return null;
|
|
772
829
|
}
|