import { getServerUrl } from "../../operation-block/helpers/get-server-url.js";
import { encode, fromUint8Array } from "js-base64";
import { shouldUseProxy } from "@scalar/helpers/url/redirect-to-proxy";
import { isRelativePath } from "@scalar/helpers/url/is-relative-path";
import { makeUrlAbsolute } from "@scalar/helpers/url/make-url-absolute";
//#region src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts
var getActiveServerBase = (activeServer, environmentVariables = {}) => {
	const serverUrl = getServerUrl(activeServer, environmentVariables);
	if (!serverUrl) return {};
	if (isRelativePath(serverUrl)) return typeof window === "undefined" ? {} : { basePath: serverUrl };
	return { baseUrl: serverUrl };
};
/**
* Generates a random string for PKCE code verifier
*
* @see https://www.rfc-editor.org/rfc/rfc7636#page-8
*/
var generateCodeVerifier = () => {
	const buffer = new Uint8Array(32);
	crypto.getRandomValues(buffer);
	return fromUint8Array(buffer, true);
};
/**
* Creates a code challenge from the code verifier
*/
var generateCodeChallenge = async (verifier, encoding) => {
	if (encoding === "plain") return verifier;
	if (typeof crypto?.subtle?.digest !== "function") {
		console.warn("SHA-256 is only supported when using https, using a plain text code challenge instead.");
		return verifier;
	}
	const data = new TextEncoder().encode(verifier);
	const digest = await crypto.subtle.digest("SHA-256", data);
	return fromUint8Array(new Uint8Array(digest), true);
};
/**
* Authorize oauth2 flow
*
* @returns the resolved oauth2 tokens
*/
var authorizeOauth2 = async (flows, type, selectedScopes, activeServer, proxyUrl, environmentVariables = {}) => {
	const flow = flows[type];
	try {
		if (!flow) return [/* @__PURE__ */ new Error("Flow not found"), null];
		const scopes = selectedScopes.join(" ");
		if (type === "clientCredentials" || type === "password") return authorizeServers(flows, type, scopes, { proxyUrl }, activeServer, environmentVariables);
		const state = (Math.random() + 1).toString(36).substring(2, 10);
		const authorizationUrl = makeUrlAbsolute(flows[type]["x-scalar-secret-auth-url"] ?? flows[type].authorizationUrl, getActiveServerBase(activeServer, environmentVariables));
		const url = new URL(authorizationUrl);
		/** Special PKCE state */
		let pkce = null;
		if (type === "implicit") url.searchParams.set("response_type", "token");
		else if (type === "authorizationCode") {
			const typedFlow = flows[type];
			url.searchParams.set("response_type", "code");
			if (typedFlow["x-usePkce"] !== "no") {
				const codeVerifier = generateCodeVerifier();
				const codeChallenge = await generateCodeChallenge(codeVerifier, typedFlow["x-usePkce"]);
				pkce = {
					codeVerifier,
					codeChallenge,
					codeChallengeMethod: typedFlow["x-usePkce"] === "SHA-256" ? "S256" : "plain"
				};
				url.searchParams.set("code_challenge", codeChallenge);
				url.searchParams.set("code_challenge_method", pkce.codeChallengeMethod);
			}
		}
		const typedFlow = flows[type];
		if (typedFlow["x-scalar-secret-redirect-uri"].startsWith("/")) {
			const baseUrl = getServerUrl(activeServer, environmentVariables) || window.location.origin + window.location.pathname;
			const redirectUri = new URL(typedFlow["x-scalar-secret-redirect-uri"], baseUrl).toString();
			url.searchParams.set("redirect_uri", redirectUri);
		} else url.searchParams.set("redirect_uri", typedFlow["x-scalar-secret-redirect-uri"]);
		if (flow["x-scalar-security-query"]) Object.keys(flow["x-scalar-security-query"]).forEach((key) => {
			const value = flow["x-scalar-security-query"]?.[key];
			if (!value) return;
			url.searchParams.set(key, value);
		});
		url.searchParams.set("client_id", flow["x-scalar-secret-client-id"]);
		url.searchParams.set("state", state);
		if (scopes) url.searchParams.set("scope", scopes);
		const authWindow = window.open(url, "openAuth2Window", "left=100,top=100,width=800,height=600");
		if (authWindow) return new Promise((resolve) => {
			const checkWindowClosed = setInterval(() => {
				let accessToken = null;
				let refreshToken = null;
				let code = null;
				let error = null;
				let errorDescription = null;
				try {
					const urlParams = new URL(authWindow.location.href).searchParams;
					const tokenName = flow["x-tokenName"] || "access_token";
					accessToken = urlParams.get(tokenName);
					refreshToken = urlParams.get("refresh_token");
					code = urlParams.get("code");
					error = urlParams.get("error");
					errorDescription = urlParams.get("error_description");
					const hashParams = new URLSearchParams(authWindow.location.href.split("#")[1]);
					accessToken ||= hashParams.get(tokenName);
					refreshToken ||= hashParams.get("refresh_token");
					code ||= hashParams.get("code");
					error ||= hashParams.get("error");
					errorDescription ||= hashParams.get("error_description");
				} catch (_e) {}
				if (authWindow.closed || accessToken || code || error) {
					clearInterval(checkWindowClosed);
					authWindow.close();
					if (error) resolve([/* @__PURE__ */ new Error(`OAuth error: ${error}${errorDescription ? ` (${errorDescription})` : ""}`), null]);
					else if (accessToken) if (authWindow.location.href.match(/state=([^&]*)/)?.[1] === state) resolve([null, {
						accessToken,
						...refreshToken ? { refreshToken } : {}
					}]);
					else resolve([/* @__PURE__ */ new Error("State mismatch"), null]);
					else if (code && type === "authorizationCode") if (new URL(authWindow.location.href).searchParams.get("state") === state) authorizeServers(flows, type, scopes, {
						code,
						pkce,
						proxyUrl
					}, activeServer, environmentVariables).then(resolve);
					else resolve([/* @__PURE__ */ new Error("State mismatch"), null]);
					else {
						clearInterval(checkWindowClosed);
						resolve([/* @__PURE__ */ new Error("Window was closed without granting authorization"), null]);
					}
				}
			}, 200);
		});
		return [/* @__PURE__ */ new Error("Failed to open auth window"), null];
	} catch (_) {
		return [/* @__PURE__ */ new Error("Failed to authorize oauth2 flow"), null];
	}
};
/**
* Makes the BE authorization call to grab the token server to server
* Used for clientCredentials and authorizationCode
*/
var authorizeServers = async (flows, type, scopes, { code, pkce, proxyUrl } = {}, activeServer, environmentVariables = {}) => {
	const flow = flows[type];
	if (!flow) return [/* @__PURE__ */ new Error("OAuth2 flow was not defined"), null];
	const formData = new URLSearchParams();
	if (scopes && (type === "clientCredentials" || type === "password")) formData.set("scope", scopes);
	/** Where to add the credentials */
	const addCredentialsToBody = flow["x-scalar-credentials-location"] === "body";
	const hasClientSecret = Boolean(flow["x-scalar-secret-client-secret"]);
	if (addCredentialsToBody || type === "authorizationCode" && !hasClientSecret) formData.set("client_id", flow["x-scalar-secret-client-id"]);
	if (addCredentialsToBody && hasClientSecret) formData.set("client_secret", flow["x-scalar-secret-client-secret"]);
	if ("x-scalar-secret-redirect-uri" in flow && flow["x-scalar-secret-redirect-uri"]) formData.set("redirect_uri", flow["x-scalar-secret-redirect-uri"]);
	if (code) {
		formData.set("code", code);
		formData.set("grant_type", "authorization_code");
		if (pkce) formData.set("code_verifier", pkce.codeVerifier);
	} else if (type === "password") {
		const typedFlow = flows[type];
		formData.set("grant_type", "password");
		formData.set("username", typedFlow["x-scalar-secret-username"]);
		formData.set("password", typedFlow["x-scalar-secret-password"]);
	} else formData.set("grant_type", "client_credentials");
	if (flow["x-scalar-security-body"]) Object.entries(flow["x-scalar-security-body"]).forEach(([key, value]) => {
		if (value) formData.set(key, String(value));
	});
	try {
		const headers = { "Content-Type": "application/x-www-form-urlencoded" };
		if (!addCredentialsToBody && hasClientSecret) headers.Authorization = `Basic ${encode(`${flow["x-scalar-secret-client-id"]}:${flow["x-scalar-secret-client-secret"]}`)}`;
		const tokenUrl = makeUrlAbsolute(flow["x-scalar-secret-token-url"] ?? flow.tokenUrl, getActiveServerBase(activeServer, environmentVariables));
		const url = shouldUseProxy(proxyUrl, tokenUrl) ? `${proxyUrl}?${new URLSearchParams([["scalar_url", tokenUrl]]).toString()}` : tokenUrl;
		const responseData = await (await fetch(url, {
			method: "POST",
			headers,
			body: formData
		})).json();
		const accessToken = responseData[flow["x-tokenName"] || "access_token"];
		const refreshToken = responseData.refresh_token;
		return [null, {
			accessToken,
			...typeof refreshToken === "string" ? { refreshToken } : {}
		}];
	} catch {
		return [/* @__PURE__ */ new Error("Failed to get an access token. Please check your credentials."), null];
	}
};
//#endregion
export { authorizeOauth2 };

//# sourceMappingURL=oauth.js.map