























@@ -2,6 +2,7 @@ import { randomBytes, randomUUID } from "node:crypto";
22import { resolveExpiresAtMsFromDurationOrEpoch } from "openclaw/plugin-sdk/number-runtime";
33import { generatePkceVerifierChallenge, toFormUrlEncoded } from "openclaw/plugin-sdk/provider-auth";
44import { ensureGlobalUndiciEnvProxyDispatcher } from "openclaw/plugin-sdk/runtime-env";
5+import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
5667export type MiniMaxRegion = "cn" | "global";
78@@ -28,6 +29,7 @@ function getOAuthEndpoints(region: MiniMaxRegion) {
2829tokenEndpoint: `${config.baseUrl}/oauth/token`,
2930clientId: config.clientId,
3031baseUrl: config.baseUrl,
32+hostname: new URL(config.baseUrl).hostname,
3133};
3234}
3335@@ -78,39 +80,47 @@ async function requestOAuthCode(params: {
7880region: MiniMaxRegion;
7981}): Promise<MiniMaxOAuthAuthorization> {
8082const endpoints = getOAuthEndpoints(params.region);
81-const response = await fetch(endpoints.codeEndpoint, {
82-method: "POST",
83-headers: {
84-"Content-Type": "application/x-www-form-urlencoded",
85-Accept: "application/json",
86-"x-request-id": randomUUID(),
83+const { response, release } = await fetchWithSsrFGuard({
84+url: endpoints.codeEndpoint,
85+init: {
86+method: "POST",
87+headers: {
88+"Content-Type": "application/x-www-form-urlencoded",
89+Accept: "application/json",
90+"x-request-id": randomUUID(),
91+},
92+body: toFormUrlEncoded({
93+response_type: "code",
94+client_id: endpoints.clientId,
95+scope: MINIMAX_OAUTH_SCOPE,
96+code_challenge: params.challenge,
97+code_challenge_method: "S256",
98+state: params.state,
99+}),
87100},
88-body: toFormUrlEncoded({
89-response_type: "code",
90-client_id: endpoints.clientId,
91-scope: MINIMAX_OAUTH_SCOPE,
92-code_challenge: params.challenge,
93-code_challenge_method: "S256",
94-state: params.state,
95-}),
101+policy: { allowedHostnames: [endpoints.hostname] },
102+auditContext: "minimax.oauth.code",
96103});
104+try {
105+if (!response.ok) {
106+const text = await response.text();
107+throw new Error(`MiniMax OAuth authorization failed: ${text || response.statusText}`);
108+}
9710998-if (!response.ok) {
99-const text = await response.text();
100-throw new Error(`MiniMax OAuth authorization failed: ${text || response.statusText}`);
101-}
102-103-const payload = (await response.json()) as MiniMaxOAuthAuthorization & { error?: string };
104-if (!payload.user_code || !payload.verification_uri) {
105-throw new Error(
106-payload.error ??
107-"MiniMax OAuth authorization returned an incomplete payload (missing user_code or verification_uri).",
108-);
109-}
110-if (payload.state !== params.state) {
111-throw new Error("MiniMax OAuth state mismatch: possible CSRF attack or session corruption.");
110+const payload = (await response.json()) as MiniMaxOAuthAuthorization & { error?: string };
111+if (!payload.user_code || !payload.verification_uri) {
112+throw new Error(
113+payload.error ??
114+"MiniMax OAuth authorization returned an incomplete payload (missing user_code or verification_uri).",
115+);
116+}
117+if (payload.state !== params.state) {
118+throw new Error("MiniMax OAuth state mismatch: possible CSRF attack or session corruption.");
119+}
120+return payload;
121+} finally {
122+await release();
112123}
113-return payload;
114124}
115125116126async function pollOAuthToken(params: {
@@ -119,20 +129,32 @@ async function pollOAuthToken(params: {
119129region: MiniMaxRegion;
120130}): Promise<TokenResult> {
121131const endpoints = getOAuthEndpoints(params.region);
122-const response = await fetch(endpoints.tokenEndpoint, {
123-method: "POST",
124-headers: {
125-"Content-Type": "application/x-www-form-urlencoded",
126-Accept: "application/json",
132+const { response, release } = await fetchWithSsrFGuard({
133+url: endpoints.tokenEndpoint,
134+init: {
135+method: "POST",
136+headers: {
137+"Content-Type": "application/x-www-form-urlencoded",
138+Accept: "application/json",
139+},
140+body: toFormUrlEncoded({
141+grant_type: MINIMAX_OAUTH_GRANT_TYPE,
142+client_id: endpoints.clientId,
143+user_code: params.userCode,
144+code_verifier: params.verifier,
145+}),
127146},
128-body: toFormUrlEncoded({
129-grant_type: MINIMAX_OAUTH_GRANT_TYPE,
130-client_id: endpoints.clientId,
131-user_code: params.userCode,
132-code_verifier: params.verifier,
133-}),
147+policy: { allowedHostnames: [endpoints.hostname] },
148+auditContext: "minimax.oauth.token",
134149});
150+try {
151+return await parseMiniMaxOAuthTokenResponse(response);
152+} finally {
153+await release();
154+}
155+}
135156157+async function parseMiniMaxOAuthTokenResponse(response: Response): Promise<TokenResult> {
136158const text = await response.text();
137159let payload:
138160| {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。