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.
Files changed (2) hide show
  1. package/dist/plugin.js +72 -12
  2. 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
- async function buildAuthHeaders(accessToken) {
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 (userId)
265
- headers["X-User-Id"] = userId;
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-codebuddy-external-auth",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "OpenCode plugin for CodeBuddy External (IOA) authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",