diff --git a/templates/definition/vehicle/ford.yaml b/templates/definition/vehicle/ford.yaml index d75000489..8c1f7213d 100644 --- a/templates/definition/vehicle/ford.yaml +++ b/templates/definition/vehicle/ford.yaml @@ -6,7 +6,11 @@ params: - preset: vehicle-identify - name: vin example: WF0FXX... + - name: domain + default: com + validvalues: ["de", "com"] render: | type: ford {{ include "vehicle-base" . }} {{ include "vehicle-identify" . }} + domain: {{ .domain }} diff --git a/vehicle/ford.go b/vehicle/ford.go index cee6f4fd5..77ed1892d 100644 --- a/vehicle/ford.go +++ b/vehicle/ford.go @@ -29,9 +29,11 @@ func NewFordFromConfig(other map[string]interface{}) (api.Vehicle, error) { cc := struct { embed `mapstructure:",squash"` User, Password, VIN string + Domain string Cache time.Duration }{ - Cache: interval, + Domain: "com", + Cache: interval, } if err := util.DecodeOther(other, &cc); err != nil { @@ -47,7 +49,7 @@ func NewFordFromConfig(other map[string]interface{}) (api.Vehicle, error) { } log := util.NewLogger("ford").Redact(cc.User, cc.Password, cc.VIN) - identity := ford.NewIdentity(log, cc.User, cc.Password) + identity := ford.NewIdentity(log, cc.User, cc.Password, cc.Domain) err := identity.Login() if err != nil { diff --git a/vehicle/ford/identity.go b/vehicle/ford/identity.go index c09626082..a9712dc65 100644 --- a/vehicle/ford/identity.go +++ b/vehicle/ford/identity.go @@ -20,7 +20,7 @@ import ( const ( TokenURI = "https://api.mps.ford.com" - LoginUri = "https://login.ford.com/4566605f-43a7-400a-946e-89cc9fdb0bd7/B2C_1A_SignInSignUp_de-DE" + LoginUriTmpl = "https://login.ford.%s/4566605f-43a7-400a-946e-89cc9fdb0bd7/B2C_1A_SignInSignUp_de-DE" ClientID = "09852200-05fd-41f6-8c21-d36d3497dc64" ApplicationID = "1E8C7794-FF5F-49BC-9596-A1E0C86C5B19" ) @@ -31,14 +31,21 @@ var loginHeaders = map[string]string{ "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1", } -var OAuth2Config = &oauth2.Config{ - ClientID: ClientID, - Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("%s/oauth2/v2.0/authorize", LoginUri), - TokenURL: fmt.Sprintf("%s/oauth2/v2.0/token", LoginUri), - }, - RedirectURL: "fordapp://userauthorized", - Scopes: []string{ClientID, "openid"}, +func NewOauth2Config(domain string) *oauth2.Config { + uri := loginUri(domain) + return &oauth2.Config{ + ClientID: ClientID, + Endpoint: oauth2.Endpoint{ + AuthURL: fmt.Sprintf("%s/oauth2/v2.0/authorize", uri), + TokenURL: fmt.Sprintf("%s/oauth2/v2.0/token", uri), + }, + RedirectURL: "fordapp://userauthorized", + Scopes: []string{ClientID, "openid"}, + } +} + +func loginUri(domain string) string { + return fmt.Sprintf(LoginUriTmpl, domain) } type Settings struct { @@ -48,16 +55,17 @@ type Settings struct { type Identity struct { *request.Helper - user, password string + user, password, domain string oauth2.TokenSource } // NewIdentity creates Ford identity -func NewIdentity(log *util.Logger, user, password string) *Identity { +func NewIdentity(log *util.Logger, user, password, domain string) *Identity { return &Identity{ Helper: request.NewHelper(log), user: user, password: password, + domain: domain, } } @@ -72,10 +80,11 @@ func (v *Identity) Login() error { // login authenticates with username/password to get new token func (v *Identity) login() (*oauth.Token, error) { - cv := oauth2.GenerateVerifier() + oc := NewOauth2Config(v.domain) + cv := oauth2.GenerateVerifier() state := lo.RandomString(16, lo.AlphanumericCharset) - uri := OAuth2Config.AuthCodeURL(state, oauth2.S256ChallengeOption(cv), + uri := oc.AuthCodeURL(state, oauth2.S256ChallengeOption(cv), oauth2.SetAuthURLParam("max_age", "3600"), oauth2.SetAuthURLParam("ui_locales", "de-DE"), oauth2.SetAuthURLParam("language_code", "de-DE"), @@ -121,7 +130,7 @@ func (v *Identity) login() (*oauth.Token, error) { } defer func() { v.Client.CheckRedirect = nil }() - uri2 := fmt.Sprintf("%s/SelfAsserted?tx=%s&p=B2C_1A_SignInSignUp_de-DE", LoginUri, settings.TransId) + uri2 := fmt.Sprintf("%s/SelfAsserted?tx=%s&p=B2C_1A_SignInSignUp_de-DE", loginUri(v.domain), settings.TransId) req, err = request.New(http.MethodPost, uri2, strings.NewReader(data.Encode()), request.URLEncoding, map[string]string{ "Accept": "*/*", "Accept-Language": "en-us", @@ -142,7 +151,7 @@ func (v *Identity) login() (*oauth.Token, error) { } } - uri3 := fmt.Sprintf("%s/api/CombinedSigninAndSignup/confirmed?rememberMe=false&csrf_token=%s&tx=%s&p=B2C_1A_SignInSignUp_de-DE", LoginUri, settings.Csrf, settings.TransId) + uri3 := fmt.Sprintf("%s/api/CombinedSigninAndSignup/confirmed?rememberMe=false&csrf_token=%s&tx=%s&p=B2C_1A_SignInSignUp_de-DE", loginUri(v.domain), settings.Csrf, settings.TransId) req, err = request.New(http.MethodGet, uri3, nil, request.URLEncoding, map[string]string{ "Origin": "https://login.ford.com", "Referer": uri, @@ -173,7 +182,7 @@ func (v *Identity) login() (*oauth.Token, error) { return nil, errors.New("could not obtain auth code- check user and password") } - tok, err := OAuth2Config.Exchange(ctx, code, oauth2.VerifierOption(cv)) + tok, err := oc.Exchange(ctx, code, oauth2.VerifierOption(cv)) // exchange code for api token var token oauth.Token