mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 17:20:41 +00:00
refactor: unify channel/plugin ssrf fetch policy and auth fallback
This commit is contained in:
71
src/plugin-sdk/fetch-auth.ts
Normal file
71
src/plugin-sdk/fetch-auth.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
export type ScopeTokenProvider = {
|
||||
getAccessToken: (scope: string) => Promise<string>;
|
||||
};
|
||||
|
||||
function isAuthFailureStatus(status: number): boolean {
|
||||
return status === 401 || status === 403;
|
||||
}
|
||||
|
||||
export async function fetchWithBearerAuthScopeFallback(params: {
|
||||
url: string;
|
||||
scopes: readonly string[];
|
||||
tokenProvider?: ScopeTokenProvider;
|
||||
fetchFn?: typeof fetch;
|
||||
requestInit?: RequestInit;
|
||||
requireHttps?: boolean;
|
||||
shouldAttachAuth?: (url: string) => boolean;
|
||||
shouldRetry?: (response: Response) => boolean;
|
||||
}): Promise<Response> {
|
||||
const fetchFn = params.fetchFn ?? fetch;
|
||||
let parsedUrl: URL;
|
||||
try {
|
||||
parsedUrl = new URL(params.url);
|
||||
} catch {
|
||||
throw new Error(`Invalid URL: ${params.url}`);
|
||||
}
|
||||
if (params.requireHttps === true && parsedUrl.protocol !== "https:") {
|
||||
throw new Error(`URL must use HTTPS: ${params.url}`);
|
||||
}
|
||||
|
||||
const fetchOnce = (headers?: Headers): Promise<Response> =>
|
||||
fetchFn(params.url, {
|
||||
...params.requestInit,
|
||||
...(headers ? { headers } : {}),
|
||||
});
|
||||
|
||||
const firstAttempt = await fetchOnce();
|
||||
if (firstAttempt.ok) {
|
||||
return firstAttempt;
|
||||
}
|
||||
if (!params.tokenProvider) {
|
||||
return firstAttempt;
|
||||
}
|
||||
|
||||
const shouldRetry =
|
||||
params.shouldRetry ?? ((response: Response) => isAuthFailureStatus(response.status));
|
||||
if (!shouldRetry(firstAttempt)) {
|
||||
return firstAttempt;
|
||||
}
|
||||
if (params.shouldAttachAuth && !params.shouldAttachAuth(params.url)) {
|
||||
return firstAttempt;
|
||||
}
|
||||
|
||||
for (const scope of params.scopes) {
|
||||
try {
|
||||
const token = await params.tokenProvider.getAccessToken(scope);
|
||||
const authHeaders = new Headers(params.requestInit?.headers);
|
||||
authHeaders.set("Authorization", `Bearer ${token}`);
|
||||
const authAttempt = await fetchOnce(authHeaders);
|
||||
if (authAttempt.ok) {
|
||||
return authAttempt;
|
||||
}
|
||||
if (!shouldRetry(authAttempt)) {
|
||||
continue;
|
||||
}
|
||||
} catch {
|
||||
// Ignore token/fetch errors and continue trying remaining scopes.
|
||||
}
|
||||
}
|
||||
|
||||
return firstAttempt;
|
||||
}
|
||||
Reference in New Issue
Block a user