diff --git a/vehicle/vw/forms.go b/vehicle/vw/forms.go index 41613e30b..0bb1daf83 100644 --- a/vehicle/vw/forms.go +++ b/vehicle/vw/forms.go @@ -1,8 +1,12 @@ package vw import ( + "encoding/json" "errors" + "fmt" "io" + "regexp" + "strings" "github.com/PuerkitoBio/goquery" ) @@ -53,3 +57,38 @@ func FormValues(reader io.Reader, id string) (FormVars, error) { return vars, err } + +type CredentialParams struct { + TemplateModel struct { + Hmac string `json:"hmac"` + RelayState string `json:"relayState"` + PostAction string `json:"postAction"` + IdentifierUrl string `json:"identifierUrl"` + Error string `json:"error"` + } `json:"templateModel"` + CurrentLocale string `json:"currentLocale"` + CsrfParameterName string `json:"csrf_parameterName"` + CsrfToken string `json:"csrf_token"` +} + +func ParseCredentialsPage(r io.ReadCloser) (CredentialParams, error) { + var res CredentialParams + + buf := new(strings.Builder) + if _, err := io.Copy(buf, r); err != nil { + return res, err + } + + re := regexp.MustCompile(`(?s)window._IDK\s*=\s*(.*?);`) + match := re.FindAllStringSubmatch(buf.String(), -1) + + tmpl := strings.ReplaceAll(match[0][1], `'`, `"`) + for _, v := range []string{`templateModel`, `currentLocale`, `csrf_parameterName`, `csrf_token`} { + tmpl = strings.Replace(tmpl, v, fmt.Sprintf(`"%s"`, v), 1) + } + + err := json.Unmarshal([]byte(tmpl), &res) + fmt.Printf("%+v\n", res) + + return res, err +} diff --git a/vehicle/vw/identity.go b/vehicle/vw/identity.go index 78abb4687..d2208f425 100644 --- a/vehicle/vw/identity.go +++ b/vehicle/vw/identity.go @@ -13,6 +13,8 @@ import ( "golang.org/x/oauth2" ) +// https://identity.vwgroup.io/.well-known/openid-configuration + const ( // IdentityURI is the VW OIDC identity provider uri IdentityURI = "https://identity.vwgroup.io" diff --git a/vehicle/vw/tokenprovider.go b/vehicle/vw/tokenprovider.go index 97d0bf0c8..91bfd98bb 100644 --- a/vehicle/vw/tokenprovider.go +++ b/vehicle/vw/tokenprovider.go @@ -1,6 +1,7 @@ package vw import ( + "errors" "fmt" "net/http" "net/http/cookiejar" @@ -70,6 +71,8 @@ func (v *IDTokenProvider) Login() (url.Values, error) { resp.Body.Close() } + var params CredentialParams + // POST identity.vwgroup.io/signin-service/v1/b7a5bb47-f875-47cf-ab83-2ba3bf6bb738@apps_vw-dilab_com/login/identifier if err == nil { data := url.Values(map[string][]string{ @@ -81,7 +84,7 @@ func (v *IDTokenProvider) Login() (url.Values, error) { uri = IdentityURI + vars.Action if resp, err = v.PostForm(uri, data); err == nil { - vars, err = FormValues(resp.Body, "form#credentialsForm") + params, err = ParseCredentialsPage(resp.Body) resp.Body.Close() } } @@ -89,17 +92,25 @@ func (v *IDTokenProvider) Login() (url.Values, error) { // POST identity.vwgroup.io/signin-service/v1/b7a5bb47-f875-47cf-ab83-2ba3bf6bb738@apps_vw-dilab_com/login/authenticate if err == nil { data := url.Values(map[string][]string{ - "_csrf": {vars.Inputs["_csrf"]}, - "relayState": {vars.Inputs["relayState"]}, - "hmac": {vars.Inputs["hmac"]}, + "_csrf": {params.CsrfToken}, + "relayState": {params.TemplateModel.RelayState}, + "hmac": {params.TemplateModel.Hmac}, "email": {v.user}, "password": {v.password}, }) - uri = IdentityURI + vars.Action + // reuse url from identifier step before + uri = strings.ReplaceAll(uri, params.TemplateModel.IdentifierUrl, params.TemplateModel.PostAction) + if resp, err = v.PostForm(uri, data); err == nil { resp.Body.Close() + if resp.StatusCode >= http.StatusBadRequest { + err = errors.New(resp.Status) + } + } + + if err == nil { if e := resp.Request.URL.Query().Get("error"); e != "" { err = fmt.Errorf(e) }