// ============================================================ // Casdoor OIDC + PKCE login — v2.6 // Config lives in /casdoor-config.js (window.CASDOOR_CONFIG), served // statically next to index.html (same values as the shipped dash). // ============================================================ const CASDOOR_CONFIG = (window as unknown as { CASDOOR_CONFIG?: CasdoorConfig }).CASDOOR_CONFIG; export interface CasdoorConfig { serverUrl: string; clientId: string; clientSecret: string; organization: string; appName: string; redirectUri: string; } function b64url(bytes: Uint8Array): string { let s = ""; for (const b of bytes) s += String.fromCharCode(b); return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); } function randomBytes(n: number): Uint8Array { const arr = new Uint8Array(n); crypto.getRandomValues(arr); return arr; } async function sha256b64url(text: string): Promise { const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text)); return b64url(new Uint8Array(buf)); } export function startCasdoorLogin(): void { if (!CASDOOR_CONFIG) { alert("تنظیمات Casdoor یافت نشد — فایل casdoor-config.js را بررسی کنید"); return; } const verifier = b64url(randomBytes(64)); const state = b64url(randomBytes(16)); sessionStorage.setItem("casdoor-pkce", JSON.stringify({ verifier, state })); void sha256b64url(verifier).then((challenge) => { const params = new URLSearchParams({ client_id: CASDOOR_CONFIG.clientId, redirect_uri: CASDOOR_CONFIG.redirectUri, response_type: "code", scope: "read", state, organization: CASDOOR_CONFIG.organization, application: CASDOOR_CONFIG.appName, code_challenge: challenge, code_challenge_method: "S256", }); window.location.href = `${CASDOOR_CONFIG.serverUrl}/login/oauth/authorize?${params.toString()}`; }); } /** Exchange the OIDC authorization code for a token (called on /callback). */ export async function exchangeCodeForToken(code: string): Promise<{ access_token: string; id_token?: string }> { if (!CASDOOR_CONFIG) throw new Error("تنظیمات Casdoor یافت نشد"); const pkce = JSON.parse(sessionStorage.getItem("casdoor-pkce") || "{}") as { verifier?: string }; const resp = await fetch(`${CASDOOR_CONFIG.serverUrl}/api/login/oauth/access_token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", client_id: CASDOOR_CONFIG.clientId, client_secret: CASDOOR_CONFIG.clientSecret, code, redirect_uri: CASDOOR_CONFIG.redirectUri, code_verifier: pkce.verifier || "", }), }); if (!resp.ok) throw new Error("خطا در دریافت توکن از Casdoor"); return resp.json(); } export { CASDOOR_CONFIG };