diff --git a/src/controllers/authStrategies/authStrategy.ts b/src/controllers/authStrategies/authStrategy.ts index b02ab58..102676a 100644 --- a/src/controllers/authStrategies/authStrategy.ts +++ b/src/controllers/authStrategies/authStrategy.ts @@ -1,6 +1,6 @@ import got from 'got'; import { CookieJar } from 'tough-cookie'; -import { DEFAULT_LANGUAGE, EULanguages, EuropeanBrandEnvironment } from '../../constants/europe'; +import { EuropeanBrandEnvironment } from '../../constants/europe'; export type Code = string; @@ -14,15 +14,11 @@ export interface AuthStrategy { export async function initSession( environment: EuropeanBrandEnvironment, - language: EULanguages = DEFAULT_LANGUAGE, cookies?: CookieJar ): Promise { const cookieJar = cookies ?? new CookieJar(); await got(environment.endpoints.session, { cookieJar }); - await got(environment.endpoints.language, { - method: 'POST', - body: `{"lang":"${language}"}`, - cookieJar, - }); + // Language endpoint now requires authentication, so we skip it + // Language will be set in the authentication URL instead return cookieJar; -} +} \ No newline at end of file diff --git a/src/controllers/authStrategies/european.brandAuth.strategy.ts b/src/controllers/authStrategies/european.brandAuth.strategy.ts index f5ea94b..3227b81 100644 --- a/src/controllers/authStrategies/european.brandAuth.strategy.ts +++ b/src/controllers/authStrategies/european.brandAuth.strategy.ts @@ -2,24 +2,13 @@ import got from 'got'; import { CookieJar } from 'tough-cookie'; import { EULanguages, EuropeanBrandEnvironment } from '../../constants/europe'; import { AuthStrategy, Code, initSession } from './authStrategy'; -import Url, { URLSearchParams } from 'url'; +import { URLSearchParams } from 'url'; const stdHeaders = { 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_1 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 Mobile/15B92 Safari/604.1', }; -const manageGot302 = >( - got: Promise> -): Promise> => { - return got.catch(error => { - if (error.name === 'HTTPError' && error.statusCode === 302) { - return error.response; - } - return Promise.reject(error); - }); -}; - export class EuropeanBrandAuthStrategy implements AuthStrategy { constructor( private readonly environment: EuropeanBrandEnvironment, @@ -30,111 +19,101 @@ export class EuropeanBrandAuthStrategy implements AuthStrategy { return 'EuropeanBrandAuthStrategy'; } - public async login(user: { username: string; password: string; }, options?: { cookieJar?: CookieJar }): Promise<{ code: Code, cookies: CookieJar }> { - const cookieJar = await initSession(this.environment, this.language, options?.cookieJar); - const { body: { userId, serviceId } } = await got(this.environment.endpoints.integration, { - cookieJar, - json: true, - headers: stdHeaders - }); - const brandAuthUrl = this.environment.brandAuthUrl({ language: this.language, userId, serviceId }); - const parsedBrandUrl = Url.parse(brandAuthUrl, true); - const { body: authForm } = await got( - brandAuthUrl, { - cookieJar, - headers: stdHeaders - }); - const actionUrl = /action="([a-z0-9:/\-.?_=&;]*)"/gi.exec(authForm); - const preparedUrl = actionUrl?.[1].replace(/&/g, '&'); - if (!preparedUrl) { - throw new Error('@EuropeanBrandAuthStrategy.login: cannot found the auth url from the form.'); - } - const formData = new URLSearchParams(); - formData.append('username', user.username); - formData.append('password', user.password); - formData.append('credentialId', ''); - formData.append('rememberMe', 'on'); - const { headers: { location: redirectTo }, body: afterAuthForm } = await manageGot302(got.post(preparedUrl, { - cookieJar, - body: formData.toString(), - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - ...stdHeaders - }, + public async login(user: { username: string; password: string; }, options?: { cookieJar?: CookieJar }): Promise<{ code: Code, cookies: CookieJar }> { + const cookieJar = await initSession(this.environment, options?.cookieJar); + + // Build the correct auth URL based on the new KIA/Hyundai authentication + const authHost = this.environment.brand === 'kia' + ? 'idpconnect-eu.kia.com' + : 'idpconnect-eu.hyundai.com'; + + const authUrl = `https://${authHost}/auth/api/v2/user/oauth2/authorize?response_type=code&client_id=${this.environment.clientId}&redirect_uri=${this.environment.baseUrl}/api/v1/user/oauth2/redirect&lang=${this.language}&state=ccsp`; + + // Step 1: GET request to auth URL to get connector_session_key + const authResponse = await got(authUrl, { + cookieJar, + headers: stdHeaders, + followRedirect: true, + throwHttpErrors: false, + }); + + // Extract connector_session_key from the final URL after redirects + const urlToCheck = authResponse.url; + + // Try multiple regex patterns to find the session key + let connectorSessionKey: string | null = null; + + // Pattern 1: URL encoded + let match = urlToCheck.match(/connector_session_key%3D([0-9a-fA-F-]{36})/); + if (match) { + connectorSessionKey = match[1]; + } + + // Pattern 2: Not URL encoded + if (!connectorSessionKey) { + match = urlToCheck.match(/connector_session_key=([0-9a-fA-F-]{36})/); + if (match) { + connectorSessionKey = match[1]; + } + } + + if (!connectorSessionKey) { + throw new Error(`@EuropeanBrandAuthStrategy.login: Could not extract connector_session_key from URL: ${urlToCheck}`); + } + + // Step 2: POST to signin endpoint + const signinUrl = `https://${authHost}/auth/account/signin`; + + const formData = new URLSearchParams(); + formData.append('client_id', this.environment.clientId); + formData.append('encryptedPassword', 'false'); + formData.append('orgHmgSid', ''); + formData.append('password', user.password); + formData.append('redirect_uri', `${this.environment.baseUrl}/api/v1/user/oauth2/redirect`); + formData.append('state', 'ccsp'); + formData.append('username', user.username); + formData.append('remember_me', 'false'); + formData.append('connector_session_key', connectorSessionKey); + formData.append('_csrf', ''); + + const signinResponse = await got.post(signinUrl, { + cookieJar, + body: formData.toString(), + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'origin': `https://${authHost}`, + ...stdHeaders + }, followRedirect: false, - })); - if(!redirectTo) { - const errorMessage = /