| const BASE64_BLOCK_SIZE = 4; |
|
|
| function validateXaiOAuthEndpoint(rawUrl, field) { |
| const value = String(rawUrl || "").trim(); |
| if (!value) throw new Error(`xai discovery ${field} is empty`); |
| let parsed; |
| try { parsed = new URL(value); } catch (err) { |
| throw new Error(`xai discovery ${field} is invalid: ${err.message}`); |
| } |
| if (parsed.protocol !== "https:") throw new Error(`xai discovery ${field} must use https: ${value}`); |
| const host = parsed.hostname.toLowerCase().trim(); |
| if (host !== "x.ai" && !host.endsWith(".x.ai")) { |
| throw new Error(`xai discovery ${field} host ${host} is not on x.ai`); |
| } |
| return value; |
| } |
|
|
| function decodeXaiIdTokenEmail(idToken) { |
| if (!idToken || typeof idToken !== "string") return undefined; |
| const parts = idToken.split("."); |
| if (parts.length !== 3) return undefined; |
| try { |
| const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/"); |
| const padding = (BASE64_BLOCK_SIZE - (base64.length % BASE64_BLOCK_SIZE)) % BASE64_BLOCK_SIZE; |
| const json = Buffer.from(base64 + "=".repeat(padding), "base64").toString("utf8"); |
| const payload = JSON.parse(json); |
| return payload.email || payload.preferred_username || payload.sub || undefined; |
| } catch { |
| return undefined; |
| } |
| } |
|
|
| function decodeJwtPayload(jwt) { |
| try { |
| if (!jwt || typeof jwt !== "string") return null; |
| const parts = jwt.split("."); |
| if (parts.length !== 3) return null; |
| const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/"); |
| const missingPadding = (BASE64_BLOCK_SIZE - (base64.length % BASE64_BLOCK_SIZE)) % BASE64_BLOCK_SIZE; |
| const padded = base64 + "=".repeat(missingPadding); |
| return JSON.parse(Buffer.from(padded, "base64").toString("utf8")); |
| } catch { |
| return null; |
| } |
| } |
|
|
| function extractEmailFromAccessToken(accessToken) { |
| const payload = decodeJwtPayload(accessToken); |
| if (!payload) return undefined; |
| return payload.email || payload.preferred_username || payload.sub || undefined; |
| } |
|
|
| export async function fetchKiroProfileArn(accessToken) { |
| if (!accessToken) return null; |
| try { |
| const response = await fetch("https://codewhisperer.us-east-1.amazonaws.com/ListAvailableProfiles", { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| Accept: "application/json", |
| Authorization: `Bearer ${accessToken}`, |
| }, |
| body: JSON.stringify({ maxResults: 10 }), |
| }); |
| if (!response.ok) return null; |
| const data = await response.json(); |
| return data.profiles?.find((p) => p.arn?.trim())?.arn?.trim() || null; |
| } catch { |
| return null; |
| } |
| } |
|
|
| export function extractCodexAccountInfo(idToken) { |
| const payload = decodeJwtPayload(idToken); |
| if (!payload) return {}; |
| const chatgpt = payload["https://api.openai.com/auth"] || {}; |
| return { |
| email: payload.email, |
| chatgptAccountId: chatgpt.chatgpt_account_id || payload.account_id, |
| chatgptPlanType: chatgpt.chatgpt_plan_type || payload.plan_type, |
| }; |
| } |
|
|
| export { |
| BASE64_BLOCK_SIZE, |
| validateXaiOAuthEndpoint, |
| decodeXaiIdTokenEmail, |
| decodeJwtPayload, |
| extractEmailFromAccessToken, |
| }; |
|
|