From 733a3843fc5f5556322565c86336f80297786e2e Mon Sep 17 00:00:00 2001 From: polskafan <52006325+polskafan@users.noreply.github.com> Date: Tue, 26 Aug 2025 07:08:54 +0200 Subject: [PATCH] Kia: fix login (#23247) --- vehicle/bluelink/identity.go | 119 +++++++++++++++++------------------ 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/vehicle/bluelink/identity.go b/vehicle/bluelink/identity.go index 3a64f7c08..973710884 100644 --- a/vehicle/bluelink/identity.go +++ b/vehicle/bluelink/identity.go @@ -247,23 +247,45 @@ func (v *Identity) brandLoginHyundaiEU(cookieClient *request.Helper, user, passw return code, err } -func (v *Identity) brandLoginKiaEU(cookieClient *request.Helper, user, password string) (string, error) { - req, _ := request.New(http.MethodGet, v.config.URI+IntegrationInfoURL, nil, request.JSONEncoding) +func (v *Identity) brandLoginKiaEU(user, password string) (string, error) { + cookieClient := request.NewHelper(v.log) + cookieClient.Client.Jar, _ = cookiejar.New(&cookiejar.Options{ + PublicSuffixList: publicsuffix.List, + }) - var info struct { - UserId string `json:"userId"` - ServiceId string `json:"serviceId"` + headers := map[string]string{ + "content-type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", } - if err := cookieClient.DoJSON(req, &info); err != nil { + data := url.Values{ + "client_id": {"peukiaidm-online-sales"}, + "encryptedPassword": {"false"}, + "password": {password}, + "redirect_uri": {"https://www.kia.com/api/bin/oneid/login"}, + "state": {"aHR0cHM6Ly93d3cua2lhLmNvbTo0NDMvZGUvP3ZlZD0yYWhVS0V3akI2ZFc3dDQtUEF4WFBSZkVESGNDQ0J4UVFnVTk2QkFnY0VBZyZfdG09MTc1NTg1NTY2ODE2Mg==_default"}, + "username": {user}, + "remember_me": {"false"}, + } + + req, _ := request.New(http.MethodPost, "https://idpconnect-eu.kia.com/auth/account/signin", strings.NewReader(data.Encode()), headers) + + if _, err := cookieClient.Do(req); err != nil { return "", err } - var resp *http.Response + v.deviceID, _ = v.getDeviceID() // get the connector_session_key - uri := fmt.Sprintf(v.config.BrandAuthUrl, v.config.LoginFormHost, v.config.AuthClientID, v.config.URI, "en") - resp, err := cookieClient.Get(uri) + uri := fmt.Sprintf(v.config.BrandAuthUrl, v.config.LoginFormHost, v.config.CCSPServiceID, v.config.URI, "en") + headers = map[string]string{ + "ccsp-application-id": v.config.CCSPApplicationID, + "ccsp-device-id": v.deviceID, + "ccsp-service-id": v.config.CCSPServiceID, + "User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", + } + req, _ = request.New(http.MethodGet, uri, nil, headers) + resp, err := cookieClient.Do(req) if err != nil { return "", err } @@ -275,44 +297,17 @@ func (v *Identity) brandLoginKiaEU(cookieClient *request.Helper, user, password return "", errors.New("empty redirect url on connector session key request") } - nextVal, err := url.Parse(nextUri) - if err != nil { - return "", err - } - - connectorSessionKey := nextVal.Query().Get("connector_session_key") - if connectorSessionKey == "" { - return "", errors.New("empty or non-existing connector session key") - } - - // if we have the connectorSessionKey, go on and find the login code - // build new request uri - uri = fmt.Sprintf("%s%s", v.config.LoginFormHost, "/auth/account/signin") - data := url.Values{ - "client_id": {v.config.CCSPServiceID}, - "encryptedPassword": {"false"}, - "orgHmgSid": {""}, - "password": {password}, - "redirect_uri": {v.config.URI + "/api/v1/user/oauth2/redirect"}, - "state": {"ccsp"}, - "username": {user}, - "remember_me": {"false"}, - "connector_session_key": {connectorSessionKey}, - "_csrf": {""}, - } - // create a client that doesn't honor redirects so we receive the original response // no idea how to do that with the internal request.New(...) function sc := http.Client{ + Jar: cookieClient.Client.Jar, + Transport: request.NewTripper(v.log, http.DefaultTransport), CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, } - req, err = request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), map[string]string{ - "Content-Type": "application/x-www-form-urlencoded", - "Origin": v.config.LoginFormHost, - }) + req, err = request.New(http.MethodGet, nextUri, nil, headers) if err != nil { return "", err } @@ -440,29 +435,29 @@ func (v *Identity) Login(user, password, language, brand string) (err error) { if user == "" || password == "" { return api.ErrMissingCredentials } - v.deviceID, err = v.getDeviceID() - - var cookieClient *request.Helper - if err == nil { - cookieClient, err = v.getCookies() - } - - if err == nil { - err = v.setLanguage(cookieClient, language) - } - var code string - if err == nil { - switch brand { - case "kia": - code, err = v.brandLoginKiaEU(cookieClient, user, password) - if err == nil { - var token *oauth2.Token - if token, err = v.exchangeCodeKiaEU(code); err == nil { - v.TokenSource = oauth.RefreshTokenSource(token, v) - } + switch brand { + case "kia": + code, err = v.brandLoginKiaEU(user, password) + if err == nil { + var token *oauth2.Token + if token, err = v.exchangeCodeKiaEU(code); err == nil { + v.TokenSource = oauth.RefreshTokenSource(token, v) } - case "hyundai": + } + case "hyundai": + v.deviceID, err = v.getDeviceID() + + var cookieClient *request.Helper + if err == nil { + cookieClient, err = v.getCookies() + } + + if err == nil { + err = v.setLanguage(cookieClient, language) + } + + if err == nil { // try new login first, then fallback if code, err = v.brandLoginHyundaiEU(cookieClient, user, password); err != nil { code, err = v.bluelinkLogin(cookieClient, user, password) @@ -473,9 +468,9 @@ func (v *Identity) Login(user, password, language, brand string) (err error) { v.TokenSource = oauth.RefreshTokenSource(token, v) } } - default: - err = fmt.Errorf("unknown brand (%s)", brand) } + default: + err = fmt.Errorf("unknown brand (%s)", brand) } if err != nil {