diff --git a/src/modules/parcel-sync/services/epay-client.ts b/src/modules/parcel-sync/services/epay-client.ts index e83f5e0..960793d 100644 --- a/src/modules/parcel-sync/services/epay-client.ts +++ b/src/modules/parcel-sync/services/epay-client.ts @@ -128,11 +128,19 @@ export class EpayClient { private async login(): Promise { // Full login URL with module + goto params (required by OpenAM) - const loginUrlFull = `${LOGIN_URL}?module=SelfRegistration&goto=${encodeURIComponent("http://epay.ancpi.ro:80/epay/LogIn.action")}`; + const gotoUrl = "http://epay.ancpi.ro:80/epay/LogIn.action"; + const loginUrlFull = `${LOGIN_URL}?module=SelfRegistration&goto=${encodeURIComponent(gotoUrl)}`; + // Step 1: GET the login page first (sets initial cookies + form tokens) + await this.client.get(loginUrlFull, { + timeout: DEFAULT_TIMEOUT_MS, + maxRedirects: 5, + validateStatus: () => true, + }); + + // Step 2: POST credentials const body = `IDToken1=${encodeURIComponent(this.username)}&IDToken2=${encodeURIComponent(this.password)}`; - // POST login — follow all redirects, let cookie jar capture everything const response = await this.client.post(loginUrlFull, body, { headers: { "Content-Type": "application/x-www-form-urlencoded", @@ -146,112 +154,66 @@ export class EpayClient { const finalUrl = response.request?.res?.responseUrl ?? response.request?.responseURL ?? - response.config?.url ?? ""; const html = typeof response.data === "string" ? response.data : ""; console.log( - `[epay] Login: status=${response.status}, finalUrl=${finalUrl.slice(0, 100)}`, + `[epay] Login POST: status=${response.status}, finalUrl=${finalUrl.slice(0, 120)}`, ); - // Auth failure: OpenAM returns login form again + // Auth failure check if ( html.includes("Authentication Failed") || - html.includes("Autentificare esuata") || - (finalUrl.includes("/openam/UI/Login") && - html.includes("IDToken1") && - html.includes("IDToken2")) + html.includes("Autentificare esuata") ) { throw new Error("ePay login failed (invalid credentials)"); } - // After redirect chain, navigate to ePay explicitly to ensure JSESSIONID - if (!finalUrl.includes("epay.ancpi.ro")) { - await this.client.get(`${BASE_URL}/LogIn.action`, { - timeout: DEFAULT_TIMEOUT_MS, - maxRedirects: 5, - validateStatus: () => true, - }); - } + // Step 3: Navigate to ePay to establish JSESSIONID + // Try the goto URL (HTTP) and HTTPS variants + const epayUrls = [gotoUrl, `${BASE_URL}/LogIn.action`]; + let loggedIn = false; - // Log all cookies for debugging - const domains = [ - "https://epay.ancpi.ro", - "https://oassl.ancpi.ro", - "http://epay.ancpi.ro", - BASE_URL, - ]; - const allCookies: Array<{ domain: string; key: string; value: string }> = []; - for (const domain of domains) { - try { - const cookies = await this.jar.getCookies(domain); - for (const c of cookies) { - allCookies.push({ - domain, - key: c.key, - value: c.value.slice(0, 15) + "...", - }); - } - } catch { - // domain not applicable - } - } - - console.log( - `[epay] Cookies after login (${allCookies.length}):`, - JSON.stringify(allCookies), - ); - - // OpenAM at ANCPI uses AMAuthCookie (not iPlanetDirectoryPro) - const SESSION_COOKIE_NAMES = [ - "AMAuthCookie", - "iPlanetDirectoryPro", - "JSESSIONID", - ]; - const hasSession = allCookies.some((c) => - SESSION_COOKIE_NAMES.includes(c.key), - ); - - if (!hasSession) { - throw new Error("ePay login failed (no session cookie)"); - } - - // Navigate to ePay to establish JSESSIONID - // CRITICAL: ePay's goto URL is HTTP (http://epay.ancpi.ro:80), not HTTPS. - // The AMAuthCookie must be sent to this exact URL for ePay to create a session. - const epayUrls = [ - "http://epay.ancpi.ro:80/epay/LogIn.action", - "http://epay.ancpi.ro/epay/LogIn.action", - `${BASE_URL}/LogIn.action`, - ]; - - let jsessionEstablished = false; for (const epayUrl of epayUrls) { try { const epayResponse = await this.client.get(epayUrl, { timeout: DEFAULT_TIMEOUT_MS, - maxRedirects: 5, + maxRedirects: 10, validateStatus: () => true, }); const epayHtml = String(epayResponse.data ?? ""); - // Check if we got the logged-in page (has credit info or user menu) if ( - epayHtml.includes("credit") || + epayHtml.includes("puncte de credit") || epayHtml.includes("LogOut") || - epayHtml.includes("Istoric") + epayHtml.includes("Istoric Comenzi") ) { - jsessionEstablished = true; + loggedIn = true; console.log(`[epay] Session established via ${epayUrl}`); break; } } catch { - // Try next URL + // Try next } } - if (!jsessionEstablished) { - console.warn("[epay] Could not establish ePay session, but AMAuthCookie is set."); + if (!loggedIn) { + // Log cookies for debugging + const cookieKeys: string[] = []; + for (const domain of [ + "https://epay.ancpi.ro", + "https://oassl.ancpi.ro", + "http://epay.ancpi.ro", + ]) { + try { + const cookies = await this.jar.getCookies(domain); + for (const c of cookies) cookieKeys.push(`${c.key}@${domain}`); + } catch { + /* skip */ + } + } + console.error(`[epay] Login failed. Cookies: ${cookieKeys.join(", ")}`); + throw new Error("ePay login failed (could not establish session)"); } console.log("[epay] Login successful.");