From dfd6dd73b2c815f739abf13e3f3c79f5574eeb9e Mon Sep 17 00:00:00 2001 From: stefan Date: Mon, 4 Aug 2025 12:20:52 +0200 Subject: [PATCH] Kia/Hyundai: fix login (#22729) --- vehicle/bluelink/identity.go | 141 ++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 67 deletions(-) diff --git a/vehicle/bluelink/identity.go b/vehicle/bluelink/identity.go index b3c49c1ff..e7ad56a1d 100644 --- a/vehicle/bluelink/identity.go +++ b/vehicle/bluelink/identity.go @@ -65,7 +65,6 @@ func NewIdentity(log *util.Logger, config Config) *Identity { } func (v *Identity) getDeviceID() (string, error) { - // stamp, err := Stamps[v.config.CCSPApplicationID].Get() stamp, err := v.stamp() if err != nil { return "", err @@ -144,88 +143,96 @@ func (v *Identity) setLanguage(cookieClient *request.Helper, language string) er } func (v *Identity) brandLogin(cookieClient *request.Helper, user, password string) (string, error) { - req, err := request.New(http.MethodGet, v.config.URI+IntegrationInfoURL, nil, request.JSONEncoding) + req, _ := request.New(http.MethodGet, v.config.URI+IntegrationInfoURL, nil, request.JSONEncoding) var info struct { UserId string `json:"userId"` ServiceId string `json:"serviceId"` } - if err == nil { - err = cookieClient.DoJSON(req, &info) + if err := cookieClient.DoJSON(req, &info); err != nil { + return "", err } var resp *http.Response // get the connector_session_key - var connectorSessionKey string - if err == nil { - uri := fmt.Sprintf(v.config.BrandAuthUrl, v.config.LoginFormHost, v.config.AuthClientID, v.config.URI, "en") - req, err = request.New(http.MethodGet, uri, nil) - if err == nil { - if resp, err = cookieClient.Do(req); err == nil { - defer resp.Body.Close() - // code adapted from hyundai_kia_connect_api - // get redirect URL from request - err = errors.New("connector session key not found") - urlRedirect := resp.Request.URL.Query() - // extract redirect URL - if nextUri := urlRedirect.Get("next_uri"); nextUri != "" { - if nextVal, ok := url.Parse(nextUri); ok == nil { - if connectorSessionKey := nextVal.Query().Get("connector_session_key"); connectorSessionKey != "" { - err = nil - } - } - } - } - } + uri := fmt.Sprintf(v.config.BrandAuthUrl, v.config.LoginFormHost, v.config.AuthClientID, v.config.URI, "en") + resp, err := cookieClient.Get(uri) + if err != nil { + return "", err + } + defer resp.Body.Close() + + // get redirect URL from request + nextUri := resp.Request.URL.Query().Get("next_uri") + if nextUri == "" { + 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 - var code string - if err == nil { - // 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{ - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - } - - req, err = http.NewRequest(http.MethodPost, uri, strings.NewReader(data.Encode())) - if err == nil { - req.PostForm = data - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - req.Header.Add("Origin", v.config.LoginFormHost) - - if resp, err = sc.Do(req); err == nil { - location := resp.Header.Get("Location") - err = errors.New("code location not found") - if locationUrl, ok := url.Parse(location); ok == nil { - if code = locationUrl.Query().Get("code"); code != "" { - err = nil - } - } - } - } + // 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": {""}, } - return code, err + // 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{ + 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, + }) + if err != nil { + return "", err + } + + resp, err = sc.Do(req) + if err != nil { + return "", err + } + + location := resp.Header.Get("Location") + if location == "" { + return "", errors.New("missing location header") + } + + locationUrl, err := url.Parse(location) + if err != nil { + return "", err + } + + code := locationUrl.Query().Get("code") + if code == "" { + return "", errors.New("missing code") + } + + return code, nil } func (v *Identity) bluelinkLogin(cookieClient *request.Helper, user, password string) (string, error) {