mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 15:14:10 +00:00
fix(google): normalize unsafe oauth expiry
This commit is contained in:
@@ -950,4 +950,34 @@ describe("loginGeminiCliOAuth", () => {
|
||||
expect(Number.isFinite(result.expires)).toBe(true);
|
||||
expect(result.expires).toBeLessThanOrEqual(beforeRefresh);
|
||||
});
|
||||
|
||||
it("keeps unsafe token expiry values out of refreshed Gemini CLI credentials", async () => {
|
||||
mockSettingsExistsSync.mockReturnValue(true);
|
||||
mockSettingsReadFileSync.mockReturnValue(
|
||||
JSON.stringify({
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: "oauth-personal",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const beforeRefresh = Date.now();
|
||||
installGeminiOAuthFetchMock(() => undefined, {
|
||||
tokenResponse: () =>
|
||||
responseJson({
|
||||
access_token: "access-token",
|
||||
expires_in: Number.MAX_SAFE_INTEGER,
|
||||
}),
|
||||
});
|
||||
const { refreshTokensForGeminiCli } = await import("./oauth.token.js");
|
||||
const result = await refreshTokensForGeminiCli({
|
||||
refresh: "refresh-token",
|
||||
email: "lobster@openclaw.ai",
|
||||
});
|
||||
|
||||
expect(Number.isSafeInteger(result.expires)).toBe(true);
|
||||
expect(result.expires).toBeLessThanOrEqual(beforeRefresh);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { resolveExpiresAtMsFromDurationSeconds } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { resolveOAuthClientConfig } from "./oauth.credentials.js";
|
||||
import { fetchWithTimeout } from "./oauth.http.js";
|
||||
import { resolveGoogleOAuthIdentity, resolveGooglePersonalOAuthIdentity } from "./oauth.project.js";
|
||||
import { isGeminiCliPersonalOAuth } from "./oauth.settings.js";
|
||||
import { REDIRECT_URI, TOKEN_URL, type GeminiCliOAuthCredentials } from "./oauth.shared.js";
|
||||
|
||||
const TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1000;
|
||||
|
||||
async function requestTokenGrant(body: URLSearchParams): Promise<{
|
||||
access_token?: string;
|
||||
refresh_token?: string;
|
||||
@@ -31,11 +34,11 @@ async function requestTokenGrant(body: URLSearchParams): Promise<{
|
||||
};
|
||||
}
|
||||
|
||||
function resolveExpiresInMs(value: unknown): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return Math.trunc(value * 1000);
|
||||
function resolveTokenExpiresAt(value: unknown): number {
|
||||
return (
|
||||
resolveExpiresAtMsFromDurationSeconds(value, { bufferMs: TOKEN_EXPIRY_BUFFER_MS }) ??
|
||||
Date.now() - TOKEN_EXPIRY_BUFFER_MS
|
||||
);
|
||||
}
|
||||
|
||||
async function buildGeminiCliCredentials(params: {
|
||||
@@ -70,8 +73,7 @@ async function buildGeminiCliCredentials(params: {
|
||||
// already-stored identity binding instead of failing token renewal.
|
||||
}
|
||||
|
||||
const expiresInMs = resolveExpiresInMs(params.tokenResponse.expires_in);
|
||||
const expiresAt = Date.now() + expiresInMs - 5 * 60 * 1000;
|
||||
const expiresAt = resolveTokenExpiresAt(params.tokenResponse.expires_in);
|
||||
|
||||
return {
|
||||
refresh: params.tokenResponse.refresh_token ?? params.refreshTokenFallback ?? "",
|
||||
|
||||
Reference in New Issue
Block a user