From 655348a731bd65c540a905686927c773e1e12b66 Mon Sep 17 00:00:00 2001 From: MarkXian Date: Tue, 28 Jul 2026 14:24:49 +0800 Subject: [PATCH] fix(oauth): normalize device timing fields --- .changeset/oauth-device-timing-fields.md | 5 +++++ packages/oauth/src/oauth.ts | 11 +++++++++-- packages/oauth/test/oauth.test.ts | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 .changeset/oauth-device-timing-fields.md diff --git a/.changeset/oauth-device-timing-fields.md b/.changeset/oauth-device-timing-fields.md new file mode 100644 index 0000000000..57b0d2dfd1 --- /dev/null +++ b/.changeset/oauth-device-timing-fields.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Handle invalid OAuth device authorization timing fields safely. diff --git a/packages/oauth/src/oauth.ts b/packages/oauth/src/oauth.ts index f55d22c2e3..fd5563279e 100644 --- a/packages/oauth/src/oauth.ts +++ b/packages/oauth/src/oauth.ts @@ -53,6 +53,13 @@ function tokenFromResponse(payload: Record): TokenInfo { }; } +function positiveNumber(value: unknown): number | undefined { + if (typeof value !== 'number' && typeof value !== 'string') return undefined; + if (typeof value === 'string' && value.trim().length === 0) return undefined; + const n = Number(value); + return Number.isFinite(n) && n > 0 ? n : undefined; +} + /** HTTP client default timeout for OAuth requests. */ const DEFAULT_HTTP_TIMEOUT_MS = 30_000; @@ -152,8 +159,8 @@ export async function requestDeviceAuthorization( deviceCode, verificationUri: typeof data['verification_uri'] === 'string' ? data['verification_uri'] : '', verificationUriComplete, - expiresIn: data['expires_in'] !== undefined ? Number(data['expires_in']) : null, - interval: Number(data['interval'] ?? 5), + expiresIn: positiveNumber(data['expires_in']) ?? null, + interval: positiveNumber(data['interval']) ?? 5, }; } diff --git a/packages/oauth/test/oauth.test.ts b/packages/oauth/test/oauth.test.ts index 2ea145631e..df04d841b0 100644 --- a/packages/oauth/test/oauth.test.ts +++ b/packages/oauth/test/oauth.test.ts @@ -264,6 +264,22 @@ describe('requestDeviceAuthorization', () => { expect(auth.interval).toBe(5); }); + it('normalizes invalid timing fields from device authorization responses', async () => { + server.enqueue('/api/oauth/device_authorization', { + status: 200, + body: { + user_code: 'U', + device_code: 'D', + verification_uri_complete: 'https://x/y', + expires_in: true, + interval: 'soon', + }, + }); + const auth = await requestAuth(); + expect(auth.expiresIn).toBeNull(); + expect(auth.interval).toBe(5); + }); + it('throws OAuthError on non-200 response', async () => { server.enqueue('/api/oauth/device_authorization', { status: 500,