opencode-codebuddy-external-auth 1.0.20 → 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 +72 -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,8 +233,25 @@ function pickFallbackModel(models) {
|
|
|
204
233
|
return "glm-4.7-ioa";
|
|
205
234
|
return models[0] || "";
|
|
206
235
|
}
|
|
207
|
-
|
|
236
|
+
function buildEnterpriseHeaders(accessToken) {
|
|
208
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
|
+
}
|
|
251
|
+
async function buildAuthHeaders(accessToken) {
|
|
252
|
+
const payload = decodeJwtPayload(accessToken);
|
|
253
|
+
const roles = payload?.realm_access?.roles || payload?.resource_access?.account?.roles;
|
|
254
|
+
let tenantId = cachedTenantId || resolveTenantId(accessToken);
|
|
209
255
|
let enterpriseId = cachedEnterpriseId || resolveEnterpriseId(accessToken);
|
|
210
256
|
const userId = cachedUserId || resolveUserId(accessToken);
|
|
211
257
|
if (!enterpriseId) {
|
|
@@ -215,6 +261,9 @@ async function buildAuthHeaders(accessToken) {
|
|
|
215
261
|
cachedModelIds = config.models;
|
|
216
262
|
}
|
|
217
263
|
}
|
|
264
|
+
if (!tenantId && enterpriseId) {
|
|
265
|
+
tenantId = enterpriseId;
|
|
266
|
+
}
|
|
218
267
|
if (tenantId)
|
|
219
268
|
cachedTenantId = tenantId;
|
|
220
269
|
if (enterpriseId)
|
|
@@ -224,6 +273,7 @@ async function buildAuthHeaders(accessToken) {
|
|
|
224
273
|
if (!warnedIdSummary) {
|
|
225
274
|
warnedIdSummary = true;
|
|
226
275
|
console.log(`[codebuddy-external] IDs: tenant=${tenantId ? "ok" : "empty"}, enterprise=${enterpriseId ? "ok" : "empty"}, user=${userId ? "ok" : "empty"}`);
|
|
276
|
+
console.log(`[codebuddy-external] Token payload: iss=${payload?.iss ? "ok" : "empty"}, sub=${payload?.sub ? "ok" : "empty"}, roles=${Array.isArray(roles) ? roles.length : 0}`);
|
|
227
277
|
}
|
|
228
278
|
if (!tenantId && !warnedTenantId) {
|
|
229
279
|
warnedTenantId = true;
|
|
@@ -240,6 +290,8 @@ async function buildAuthHeaders(accessToken) {
|
|
|
240
290
|
const conversationId = generateUuid();
|
|
241
291
|
const messageId = generateUuid();
|
|
242
292
|
const requestId = messageId;
|
|
293
|
+
const traceHeaders = buildTraceHeaders();
|
|
294
|
+
const encodedUserId = userId ? encodeURIComponent(userId) : "";
|
|
243
295
|
const headers = {
|
|
244
296
|
"Accept": "application/json",
|
|
245
297
|
"Content-Type": "application/json",
|
|
@@ -256,13 +308,14 @@ async function buildAuthHeaders(accessToken) {
|
|
|
256
308
|
"X-Domain": CONFIG.domain,
|
|
257
309
|
"X-Product": CONFIG.product,
|
|
258
310
|
"User-Agent": `CLI/${CONFIG.appVersion} CodeBuddy/${CONFIG.appVersion}`,
|
|
311
|
+
...traceHeaders,
|
|
259
312
|
};
|
|
260
313
|
if (tenantId)
|
|
261
314
|
headers["X-Tenant-Id"] = tenantId;
|
|
262
315
|
if (enterpriseId)
|
|
263
316
|
headers["X-Enterprise-Id"] = enterpriseId;
|
|
264
|
-
if (
|
|
265
|
-
headers["X-User-Id"] =
|
|
317
|
+
if (encodedUserId)
|
|
318
|
+
headers["X-User-Id"] = encodedUserId;
|
|
266
319
|
return headers;
|
|
267
320
|
}
|
|
268
321
|
/**
|
|
@@ -500,7 +553,7 @@ async function executeViaAuthApi(openaiRequest, auth) {
|
|
|
500
553
|
};
|
|
501
554
|
let response = await doRequest(accessToken);
|
|
502
555
|
if ((response.status === 401 || response.status === 403) && auth.refresh) {
|
|
503
|
-
const refreshed = await refreshAccessToken(auth.refresh);
|
|
556
|
+
const refreshed = await refreshAccessToken(auth.refresh, accessToken);
|
|
504
557
|
if (refreshed?.accessToken) {
|
|
505
558
|
accessToken = refreshed.accessToken;
|
|
506
559
|
response = await doRequest(accessToken);
|
|
@@ -713,15 +766,22 @@ async function pollForToken(state, expiresAt, signal) {
|
|
|
713
766
|
/**
|
|
714
767
|
* Refresh the access token
|
|
715
768
|
*/
|
|
716
|
-
async function refreshAccessToken(refreshToken) {
|
|
769
|
+
async function refreshAccessToken(refreshToken, accessToken) {
|
|
717
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
|
+
}
|
|
718
782
|
const response = await fetch(`${CONFIG.serverUrl}/v2/plugin/auth/token/refresh`, {
|
|
719
783
|
method: "POST",
|
|
720
|
-
headers
|
|
721
|
-
"Content-Type": "application/json",
|
|
722
|
-
"Accept": "application/json",
|
|
723
|
-
"Authorization": `Bearer ${refreshToken}`,
|
|
724
|
-
},
|
|
784
|
+
headers,
|
|
725
785
|
});
|
|
726
786
|
if (!response.ok) {
|
|
727
787
|
console.warn(`[codebuddy-external] Token refresh failed: ${response.status}`);
|
|
@@ -763,7 +823,7 @@ const CodeBuddyExternalAuthPlugin = async (_input) => {
|
|
|
763
823
|
if (auth.type !== "oauth" || !auth.refresh) {
|
|
764
824
|
return null;
|
|
765
825
|
}
|
|
766
|
-
const tokenData = await refreshAccessToken(auth.refresh);
|
|
826
|
+
const tokenData = await refreshAccessToken(auth.refresh, auth.access);
|
|
767
827
|
if (!tokenData) {
|
|
768
828
|
return null;
|
|
769
829
|
}
|