From 07c559b4c746b41f7fe8960dcd12503279e7c236 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 29 Dec 2021 22:13:24 +0100 Subject: [PATCH] Porsche: fix token refresh after refactoring (#2152) --- vehicle/porsche.go | 4 +-- vehicle/porsche/identity.go | 57 +++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/vehicle/porsche.go b/vehicle/porsche.go index 2e3f1a3a5..e8baecff0 100644 --- a/vehicle/porsche.go +++ b/vehicle/porsche.go @@ -40,9 +40,9 @@ func NewPorscheFromConfig(other map[string]interface{}) (api.Vehicle, error) { } log := util.NewLogger("porsche").Redact(cc.User, cc.Password, cc.VIN) - identity := porsche.NewIdentity(log) + identity := porsche.NewIdentity(log, cc.User, cc.Password) - err := identity.Login(cc.User, cc.Password) + err := identity.Login() if err != nil { return nil, fmt.Errorf("login failed: %w", err) } diff --git a/vehicle/porsche/identity.go b/vehicle/porsche/identity.go index a9ff23bbd..3a27b54d9 100644 --- a/vehicle/porsche/identity.go +++ b/vehicle/porsche/identity.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/oauth" "github.com/evcc-io/evcc/util/request" cv "github.com/nirasan/go-oauth-pkce-code-verifier" "golang.org/x/net/publicsuffix" @@ -42,27 +43,41 @@ var ( // Identity is the Porsche Identity client type Identity struct { - log *util.Logger *request.Helper + user, password string + defaultToken, emobilityToken *oauth2.Token DefaultSource, EmobilitySource oauth2.TokenSource } // NewIdentity creates Porsche identity -func NewIdentity(log *util.Logger) *Identity { +func NewIdentity(log *util.Logger, user, password string) *Identity { v := &Identity{ - log: log, - Helper: request.NewHelper(log), + Helper: request.NewHelper(log), + user: user, + password: password, } return v } -func (v *Identity) Login(user, password string) error { +func (v *Identity) Login() error { + _, err := v.RefreshToken(nil) + + if err == nil { + v.DefaultSource = oauth.RefreshTokenSource(v.defaultToken, v) + v.EmobilitySource = oauth.RefreshTokenSource(v.emobilityToken, &emobilityAdapter{v}) + } + + return err +} + +// RefreshToken performs new login and creates default and emobility tokens +func (v *Identity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) { jar, err := cookiejar.New(&cookiejar.Options{ PublicSuffixList: publicsuffix.List, }) if err != nil { - return err + return nil, err } // track cookies and follow all (>10) redirects @@ -79,13 +94,13 @@ func (v *Identity) Login(user, password string) error { uri := fmt.Sprintf("%s/auth/api/v1/de/de_DE/public/login", OAuthURI) resp, err := v.Get(uri) if err != nil { - return err + return nil, err } resp.Body.Close() query, err := url.ParseQuery(resp.Request.URL.RawQuery) if err != nil { - return err + return nil, err } sec := query.Get("sec") @@ -98,33 +113,33 @@ func (v *Identity) Login(user, password string) error { "resume": []string{resume}, "thirdPartyId": []string{thirdPartyID}, "state": []string{state}, - "username": []string{user}, - "password": []string{password}, + "username": []string{v.user}, + "password": []string{v.password}, "keeploggedin": []string{"false"}, } req, err := request.New(http.MethodPost, uri, strings.NewReader(dataLoginAuth.Encode()), request.URLEncoding) if err != nil { - return err + return nil, err } // process the auth so the session is authenticated if resp, err = v.Client.Do(req); err != nil { - return err + return nil, err } resp.Body.Close() // get the token for the generic API token, err := v.fetchToken(OAuth2Config) if err == nil { - v.DefaultSource = OAuth2Config.TokenSource(context.Background(), token) + v.defaultToken = token if token, err = v.fetchToken(EmobilityOAuth2Config); err == nil { - v.EmobilitySource = EmobilityOAuth2Config.TokenSource(context.Background(), token) + v.emobilityToken = token } } - return err + return v.defaultToken, err } func (v *Identity) fetchToken(oc *oauth2.Config) (*oauth2.Token, error) { @@ -168,3 +183,15 @@ func (v *Identity) fetchToken(oc *oauth2.Config) (*oauth2.Token, error) { return token, err } + +type emobilityAdapter struct { + tr *Identity +} + +func (v *emobilityAdapter) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) { + token, err := v.tr.RefreshToken(nil) + if err == nil { + token = v.tr.emobilityToken + } + return token, err +}