chore: switch to ReuseTokenSource (#26206)
This commit is contained in:
parent
6a11785633
commit
19a30ac9ca
27 changed files with 137 additions and 108 deletions
|
|
@ -48,7 +48,7 @@ func TokenSource(log *util.Logger, user, password string) (oauth2.TokenSource, e
|
|||
|
||||
token, err := c.authenticate()
|
||||
|
||||
return oauth.RefreshTokenSource(token.AsOAuth2Token(), c), err
|
||||
return oauth.RefreshTokenSource(token.AsOAuth2Token(), c.refreshToken), err
|
||||
}
|
||||
|
||||
func (c *tokenSource) authenticate() (*Token, error) {
|
||||
|
|
@ -72,7 +72,7 @@ func (c *tokenSource) authenticate() (*Token, error) {
|
|||
return &token, err
|
||||
}
|
||||
|
||||
func (c *tokenSource) RefreshToken(oauthToken *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (c *tokenSource) refreshToken(oauthToken *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
RefreshToken string `json:"refreshToken"`
|
||||
|
|
|
|||
|
|
@ -62,14 +62,14 @@ func TokenSource(log *util.Logger, uri, user, password string) (oauth2.TokenSour
|
|||
if err == nil {
|
||||
var token Token
|
||||
if err = c.DoJSON(req, &token); err == nil {
|
||||
c.TokenSource = oauth.RefreshTokenSource(token.AsOAuth2Token(), c)
|
||||
c.TokenSource = oauth.RefreshTokenSource(token.AsOAuth2Token(), c.refreshToken)
|
||||
}
|
||||
}
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (c *tokenSource) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (c *tokenSource) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"refresh_token": {token.RefreshToken},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/oauth"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
|
@ -15,10 +14,10 @@ type tokenSource struct {
|
|||
}
|
||||
|
||||
func TokenSource(log *util.Logger, token *oauth2.Token) oauth2.TokenSource {
|
||||
return oauth.RefreshTokenSource(token, &tokenSource{log})
|
||||
return oauth2.ReuseTokenSource(token, &tokenSource{log})
|
||||
}
|
||||
|
||||
func (ts *tokenSource) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (ts *tokenSource) Token() (*oauth2.Token, error) {
|
||||
// "Content-Type: application/json" \
|
||||
// --request POST \
|
||||
// https://console.corrently.io/v2.0/auth/requestToken
|
||||
|
|
|
|||
|
|
@ -79,13 +79,13 @@ func NewEdfTempoFromConfig(other map[string]any) (api.Tariff, error) {
|
|||
|
||||
t.Client.Transport = &oauth2.Transport{
|
||||
Base: t.Client.Transport,
|
||||
Source: oauth.RefreshTokenSource(new(oauth2.Token), t),
|
||||
Source: oauth2.ReuseTokenSource(nil, oauth.BootstrapTokenSource(t.refreshToken)),
|
||||
}
|
||||
|
||||
return runOrError(t)
|
||||
}
|
||||
|
||||
func (t *EdfTempo) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (t *EdfTempo) refreshToken() (*oauth2.Token, error) {
|
||||
tokenURL := "https://digital.iservices.rte-france.com/token/oauth"
|
||||
req, _ := request.New(http.MethodPost, tokenURL, nil, map[string]string{
|
||||
"Authorization": t.basic,
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/oauth"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/transport"
|
||||
"github.com/hasura/go-graphql-client"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// BaseURI is Octopus Energy Germany's Kraken API root.
|
||||
|
|
@ -28,7 +28,7 @@ type OctopusDeGraphQLClient struct {
|
|||
|
||||
// NewClient returns a new, authenticated instance of OctopusDeGraphQLClient.
|
||||
func NewClient(log *util.Logger, email, password, accountNumber string) (*OctopusDeGraphQLClient, error) {
|
||||
ts := oauth.RefreshTokenSource(nil, &TokenSource{
|
||||
ts := oauth2.ReuseTokenSource(nil, &tokenSource{
|
||||
log: log,
|
||||
email: email,
|
||||
password: password,
|
||||
|
|
|
|||
|
|
@ -12,25 +12,27 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type TokenSource struct {
|
||||
type tokenSource struct {
|
||||
log *util.Logger
|
||||
email, password string
|
||||
}
|
||||
|
||||
var _ oauth2.TokenSource = (*tokenSource)(nil)
|
||||
|
||||
// RefreshToken implements oauth.TokenRefresher to obtain a new JWT token.
|
||||
// It parses the JWT to extract the actual expiry time from the token claims.
|
||||
func (c *TokenSource) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (ts *tokenSource) Token() (*oauth2.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
// Create a temporary client without authentication for the token request
|
||||
cli := request.NewClient(c.log)
|
||||
cli := request.NewClient(ts.log)
|
||||
tempClient := graphql.NewClient(BaseURI, cli)
|
||||
|
||||
var q krakenTokenAuthentication
|
||||
if err := tempClient.Mutate(ctx, &q, map[string]any{
|
||||
"email": c.email,
|
||||
"password": c.password,
|
||||
"email": ts.email,
|
||||
"password": ts.password,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("authentication failed: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ func NewOstromFromConfig(other map[string]any) (api.Tariff, error) {
|
|||
|
||||
t.Client.Transport = &oauth2.Transport{
|
||||
Base: t.Client.Transport,
|
||||
Source: oauth.RefreshTokenSource(nil, t),
|
||||
Source: oauth2.ReuseTokenSource(nil, oauth.BootstrapTokenSource(t.refreshToken)),
|
||||
}
|
||||
|
||||
contracts, err := t.getContracts()
|
||||
|
|
@ -158,7 +158,7 @@ func (t *Ostrom) getFixedPrice() (float64, error) {
|
|||
return 0, errors.New("tariff not found")
|
||||
}
|
||||
|
||||
func (t *Ostrom) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (t *Ostrom) refreshToken() (*oauth2.Token, error) {
|
||||
uri := ostrom.URI_AUTH + "/oauth2/token"
|
||||
data := url.Values{"grant_type": {"client_credentials"}}
|
||||
req, _ := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), map[string]string{
|
||||
|
|
|
|||
25
util/oauth/bootstraptokensource.go
Normal file
25
util/oauth/bootstraptokensource.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package oauth
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type bootstrapTokenSource struct {
|
||||
mu sync.Mutex
|
||||
refresher func() (*oauth2.Token, error)
|
||||
}
|
||||
|
||||
func BootstrapTokenSource(refresher func() (*oauth2.Token, error)) oauth2.TokenSource {
|
||||
return &bootstrapTokenSource{
|
||||
refresher: refresher,
|
||||
}
|
||||
}
|
||||
|
||||
func (ts *bootstrapTokenSource) Token() (*oauth2.Token, error) {
|
||||
ts.mu.Lock()
|
||||
defer ts.mu.Unlock()
|
||||
|
||||
return ts.refresher()
|
||||
}
|
||||
|
|
@ -7,23 +7,19 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type TokenRefresher interface {
|
||||
RefreshToken(token *oauth2.Token) (*oauth2.Token, error)
|
||||
}
|
||||
|
||||
type TokenSource struct {
|
||||
type refreshTokenSource struct {
|
||||
mu sync.Mutex
|
||||
token *oauth2.Token
|
||||
refresher TokenRefresher
|
||||
refresher func(token *oauth2.Token) (*oauth2.Token, error)
|
||||
}
|
||||
|
||||
func RefreshTokenSource(token *oauth2.Token, refresher TokenRefresher) oauth2.TokenSource {
|
||||
func RefreshTokenSource(token *oauth2.Token, refresher func(token *oauth2.Token) (*oauth2.Token, error)) oauth2.TokenSource {
|
||||
if token == nil {
|
||||
// allocate an (expired) token or mergeToken will fail
|
||||
token = new(oauth2.Token)
|
||||
}
|
||||
|
||||
ts := &TokenSource{
|
||||
ts := &refreshTokenSource{
|
||||
token: token,
|
||||
refresher: refresher,
|
||||
}
|
||||
|
|
@ -31,7 +27,7 @@ func RefreshTokenSource(token *oauth2.Token, refresher TokenRefresher) oauth2.To
|
|||
return ts
|
||||
}
|
||||
|
||||
func (ts *TokenSource) Token() (*oauth2.Token, error) {
|
||||
func (ts *refreshTokenSource) Token() (*oauth2.Token, error) {
|
||||
ts.mu.Lock()
|
||||
defer ts.mu.Unlock()
|
||||
|
||||
|
|
@ -39,7 +35,7 @@ func (ts *TokenSource) Token() (*oauth2.Token, error) {
|
|||
return ts.token, nil
|
||||
}
|
||||
|
||||
token, err := ts.refresher.RefreshToken(ts.token)
|
||||
token, err := ts.refresher(ts.token)
|
||||
if err != nil {
|
||||
return ts.token, err
|
||||
}
|
||||
|
|
@ -8,24 +8,20 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type tkr struct{}
|
||||
|
||||
func (tkr *tkr) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
return (&oauth2.Token{
|
||||
AccessToken: "new",
|
||||
}).WithExtra(map[string]any{
|
||||
"foo": "bar",
|
||||
}), nil
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
ts := &TokenSource{
|
||||
ts := &refreshTokenSource{
|
||||
token: &oauth2.Token{
|
||||
AccessToken: "access",
|
||||
RefreshToken: "refresh",
|
||||
Expiry: time.Now(),
|
||||
},
|
||||
refresher: new(tkr),
|
||||
refresher: func(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
return (&oauth2.Token{
|
||||
AccessToken: "new",
|
||||
}).WithExtra(map[string]any{
|
||||
"foo": "bar",
|
||||
}), nil
|
||||
},
|
||||
}
|
||||
|
||||
r, err := ts.Token()
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// TokenWithExpiry decorates an oauth2.Token with the expiry from the ExpiresIn property
|
||||
func TokenWithExpiry(token *oauth2.Token) *oauth2.Token {
|
||||
if token != nil && token.Expiry.IsZero() && token.ExpiresIn != 0 {
|
||||
token.Expiry = time.Now().Add(time.Second * time.Duration(token.ExpiresIn))
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ func (v *Identity) getDeviceID() (string, error) {
|
|||
return res.ResMsg.DeviceID, err
|
||||
}
|
||||
|
||||
// RefreshToken implements oauth.TokenRefresher
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
// refreshToken renews BlueLink OAuth tokens
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
var res oauth2.Token
|
||||
|
||||
uri := v.config.LoginFormHost + TokenURL
|
||||
|
|
@ -144,11 +144,11 @@ func (v *Identity) Login(user, password, language, brand string) (err error) {
|
|||
return fmt.Errorf("unknown brand (%s)", brand)
|
||||
}
|
||||
|
||||
token, err := v.RefreshToken(&oauth2.Token{RefreshToken: password})
|
||||
token, err := v.refreshToken(&oauth2.Token{RefreshToken: password})
|
||||
if err != nil {
|
||||
return fmt.Errorf("login failed: %w", err)
|
||||
}
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
|
||||
|
||||
v.deviceID, err = v.getDeviceID()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func (v *Identity) Login() error {
|
|||
return fmt.Errorf("login failed: %w", err)
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
v.TokenSource = oauth2.ReuseTokenSource(token, oauth.BootstrapTokenSource(v.login))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -96,9 +96,3 @@ func (v *Identity) login() (*oauth2.Token, error) {
|
|||
Expiry: time.Now().Add(time.Duration(expiresIn) * time.Second),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RefreshToken implements oauth.TokenRefresher
|
||||
// US API doesn't have a refresh endpoint, so we re-login with credentials
|
||||
func (v *Identity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
return v.login()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ func (v *Identity) Login(user, password, hcaptcha string) (oauth2.TokenSource, e
|
|||
var tok oauth2.Token
|
||||
if err := settings.Json(v.settingsKey(), &tok); err == nil {
|
||||
v.log.DEBUG.Println("identity.Login - database token found")
|
||||
tok, err := v.RefreshToken(&tok)
|
||||
tok, err := v.refreshToken(&tok)
|
||||
if err == nil {
|
||||
ts := oauth2.ReuseTokenSourceWithExpiry(tok, oauth.RefreshTokenSource(tok, v), 15*time.Minute)
|
||||
ts := oauth2.ReuseTokenSourceWithExpiry(tok, oauth.RefreshTokenSource(tok, v.refreshToken), 15*time.Minute)
|
||||
return ts, nil
|
||||
}
|
||||
v.log.DEBUG.Println("identity.Login - database token invalid. Proceeding to login via user, password and captcha.")
|
||||
|
|
@ -150,7 +150,7 @@ func (v *Identity) Login(user, password, hcaptcha string) (oauth2.TokenSource, e
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ts := oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v), 15*time.Minute)
|
||||
ts := oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v.refreshToken), 15*time.Minute)
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
|
@ -179,7 +179,7 @@ func (v *Identity) retrieveToken(data url.Values) (*oauth2.Token, error) {
|
|||
return tokex, err
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := url.Values{
|
||||
"redirect_uri": {RedirectURI},
|
||||
"refresh_token": {token.RefreshToken},
|
||||
|
|
|
|||
|
|
@ -71,14 +71,14 @@ func (v *Identity) Login() (Token, error) {
|
|||
|
||||
token, err := v.login(data)
|
||||
if err == nil {
|
||||
v.TokenSource = oauth.RefreshTokenSource(&token.Token, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(&token.Token, v.refreshToken)
|
||||
}
|
||||
|
||||
return token, err
|
||||
}
|
||||
|
||||
// RefreshToken implements oauth.TokenRefresher
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
// refreshToken renews the JLR token
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := map[string]string{
|
||||
"grant_type": "refresh_token",
|
||||
"refresh_token": token.RefreshToken,
|
||||
|
|
|
|||
|
|
@ -75,14 +75,14 @@ func NewIdentity(log *util.Logger, token *oauth2.Token, account string, region s
|
|||
|
||||
if !token.Valid() && token.RefreshToken != "" {
|
||||
v.log.DEBUG.Println("identity.NewIdentity - refreshToken started")
|
||||
if tok, err := v.RefreshToken(token); err == nil {
|
||||
if tok, err := v.refreshToken(token); err == nil {
|
||||
token = tok
|
||||
}
|
||||
}
|
||||
|
||||
if !token.Valid() {
|
||||
v.log.DEBUG.Println("identity.NewIdentity - config refreshToken started")
|
||||
if tok, err := v.RefreshToken(configToken); err == nil {
|
||||
if tok, err := v.refreshToken(configToken); err == nil {
|
||||
token = tok
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ func NewIdentity(log *util.Logger, token *oauth2.Token, account string, region s
|
|||
return nil, errors.New("token expired")
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
|
||||
|
||||
// add instance
|
||||
addInstance(account, v)
|
||||
|
|
@ -103,7 +103,7 @@ func (v *Identity) settingsKey() string {
|
|||
return fmt.Sprintf("mercedes.%s-%s", v.account, v.region)
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
|||
}
|
||||
|
||||
tok := util.TokenWithExpiry(&res)
|
||||
v.TokenSource = oauth.RefreshTokenSource(tok, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(tok, v.refreshToken)
|
||||
|
||||
err := settings.SetJson(v.settingsKey(), tok)
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func NewIdentity(log *util.Logger, user, password string) (oauth2.TokenSource, e
|
|||
return nil, err
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
|
@ -149,8 +149,8 @@ func (v *Identity) login() (*oauth2.Token, error) {
|
|||
return util.TokenWithExpiry(&token), nil
|
||||
}
|
||||
|
||||
// Token implements oauth.TokenSource
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
// refreshToken obtains a renewed oauth token
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"refresh_token": {token.RefreshToken},
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func NewIdentity(log *util.Logger, user, password string) (oauth2.TokenSource, e
|
|||
return nil, fmt.Errorf("login failed: %w", err)
|
||||
}
|
||||
|
||||
return oauth.RefreshTokenSource(token, v), nil
|
||||
return oauth.RefreshTokenSource(token, v.refreshToken), nil
|
||||
}
|
||||
|
||||
func (v *Identity) login() (*oauth2.Token, error) {
|
||||
|
|
@ -168,7 +168,7 @@ func (v *Identity) login() (*oauth2.Token, error) {
|
|||
return OAuth2Config.Exchange(ctx, code, oauth2.VerifierOption(cv))
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, v.Client)
|
||||
ts := oauth2.ReuseTokenSource(token, OAuth2Config.TokenSource(ctx, token))
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func NewIdentity(log *util.Logger, brand, user string, oc *oauth2.Config, token
|
|||
}
|
||||
|
||||
if !token.Valid() {
|
||||
if tok, err := v.RefreshToken(token); err == nil {
|
||||
if tok, err := v.refreshToken(token); err == nil {
|
||||
token = tok
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ func NewIdentity(log *util.Logger, brand, user string, oc *oauth2.Config, token
|
|||
return nil, errors.New("token expired")
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
|
||||
|
||||
// add instance
|
||||
addInstance(v.subject, v)
|
||||
|
|
@ -62,7 +62,7 @@ func NewIdentity(log *util.Logger, brand, user string, oc *oauth2.Config, token
|
|||
return v, nil
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(tok, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(tok, v.refreshToken)
|
||||
err = settings.SetJson(v.subject, tok)
|
||||
|
||||
return tok, err
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func (v *Identity) Login() error {
|
|||
return err
|
||||
}
|
||||
|
||||
v.TokenSource = oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v), 15*time.Minute)
|
||||
v.TokenSource = oauth2.ReuseTokenSourceWithExpiry(token, oauth.RefreshTokenSource(token, v.refreshToken), 15*time.Minute)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ func (v *Identity) retrieveToken(data url.Values) (*oauth2.Token, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := url.Values{
|
||||
"refresh_token": {token.RefreshToken},
|
||||
"grant_type": {"refresh_token"},
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ func NewIdentity(log *util.Logger, user, password string) (*Identity, error) {
|
|||
deviceID: lo.RandomString(16, lo.AlphanumericCharset),
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(nil, v)
|
||||
v.TokenSource = oauth2.ReuseTokenSource(nil, oauth.BootstrapTokenSource(v.refreshToken))
|
||||
|
||||
_, err := v.Token()
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken() (*oauth2.Token, error) {
|
||||
token, err := v.login()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -149,11 +149,11 @@ func (v *Identity) fetchTokenCredentials(code string) error {
|
|||
}
|
||||
|
||||
v.uuid = uuid
|
||||
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v.refreshToken)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
uri := fmt.Sprintf("%s/%s", BaseUrl, AccessTokenPath)
|
||||
data := url.Values{
|
||||
"client_id": {ClientID},
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func NewIdentity(log *util.Logger, oc *oauth2.Config, token *oauth2.Token) (oaut
|
|||
}
|
||||
|
||||
if !token.Valid() && token.RefreshToken != "" {
|
||||
if tok, err := v.RefreshToken(token); err == nil {
|
||||
if tok, err := v.refreshToken(token); err == nil {
|
||||
token = tok
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +83,7 @@ func NewIdentity(log *util.Logger, oc *oauth2.Config, token *oauth2.Token) (oaut
|
|||
return nil, errors.New("token expired")
|
||||
}
|
||||
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v.refreshToken)
|
||||
|
||||
// add instance
|
||||
addInstance(claims.Subject, v)
|
||||
|
|
@ -95,7 +95,7 @@ func (v *Identity) settingsKey() string {
|
|||
return fmt.Sprintf("tesla-command.%s", v.subject)
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
|
||||
|
|
|
|||
|
|
@ -138,11 +138,11 @@ func (v *Identity) fetchTokenCredentials(code string) error {
|
|||
}
|
||||
|
||||
v.uuid = uuid
|
||||
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v)
|
||||
v.TokenSource = oauth.RefreshTokenSource(util.TokenWithExpiry(&res.Token), v.refreshToken)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
func (v *Identity) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
uri := fmt.Sprintf("%s/%s", BaseUrl, AccessTokenPath)
|
||||
data := url.Values{
|
||||
"client_id": {ClientID},
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import (
|
|||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/oauth"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
"github.com/evcc-io/evcc/vehicle/tronity"
|
||||
|
|
@ -95,7 +94,7 @@ func NewTronityFromConfig(other map[string]any) (api.Vehicle, error) {
|
|||
// https://app.platform.tronity.io/docs#tag/Authentication
|
||||
if err != nil {
|
||||
// use app flow if we don't have tokens
|
||||
ts = oauth.RefreshTokenSource(nil, v)
|
||||
ts = tronity.TokenSource(log, oc)
|
||||
} else {
|
||||
// use provided tokens generated by code flow
|
||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewClient(log))
|
||||
|
|
@ -139,26 +138,6 @@ func NewTronityFromConfig(other map[string]any) (api.Vehicle, error) {
|
|||
return decorateTronity(v, status, odometer, chargeEnable), nil
|
||||
}
|
||||
|
||||
// RefreshToken performs token refresh by logging in with app context
|
||||
func (v *Tronity) RefreshToken(_ *oauth2.Token) (*oauth2.Token, error) {
|
||||
data := struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
GrantType string `json:"grant_type"`
|
||||
}{
|
||||
ClientID: v.oc.ClientID,
|
||||
ClientSecret: v.oc.ClientSecret,
|
||||
GrantType: "app",
|
||||
}
|
||||
|
||||
req, _ := request.New(http.MethodPost, v.oc.Endpoint.TokenURL, request.MarshalJSON(data), request.JSONEncoding)
|
||||
|
||||
var token oauth2.Token
|
||||
err := request.NewHelper(v.log).DoJSON(req, &token)
|
||||
|
||||
return util.TokenWithExpiry(&token), err
|
||||
}
|
||||
|
||||
// vehicles implements the vehicles api
|
||||
func (v *Tronity) vehicles() ([]tronity.Vehicle, error) {
|
||||
uri := fmt.Sprintf("%s/tronity/vehicles", tronity.URI)
|
||||
|
|
|
|||
37
vehicle/tronity/tokensource.go
Normal file
37
vehicle/tronity/tokensource.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package tronity
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type tokenSource struct {
|
||||
log *util.Logger
|
||||
oc *oauth2.Config
|
||||
}
|
||||
|
||||
func TokenSource(log *util.Logger, oc *oauth2.Config) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSource(nil, &tokenSource{log, oc})
|
||||
}
|
||||
|
||||
func (ts *tokenSource) Token() (*oauth2.Token, error) {
|
||||
data := struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
GrantType string `json:"grant_type"`
|
||||
}{
|
||||
ClientID: ts.oc.ClientID,
|
||||
ClientSecret: ts.oc.ClientSecret,
|
||||
GrantType: "app",
|
||||
}
|
||||
|
||||
req, _ := request.New(http.MethodPost, ts.oc.Endpoint.TokenURL, request.MarshalJSON(data), request.JSONEncoding)
|
||||
|
||||
var token oauth2.Token
|
||||
err := request.NewHelper(ts.log).DoJSON(req, &token)
|
||||
|
||||
return util.TokenWithExpiry(&token), err
|
||||
}
|
||||
|
|
@ -84,13 +84,13 @@ func (v *Service) Refresh(token *Token) (*Token, error) {
|
|||
return &t, err
|
||||
}
|
||||
|
||||
// RefreshToken implements oauth.TokenRefresher
|
||||
func (v *Service) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
// refreshToken renews the LoginApps token
|
||||
func (v *Service) refreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
res, err := v.Refresh((*Token)(token))
|
||||
return (*oauth2.Token)(res), err
|
||||
}
|
||||
|
||||
// TokenSource creates a refreshing oauth2 token source
|
||||
func (v *Service) TokenSource(token *Token) oauth2.TokenSource {
|
||||
return oauth.RefreshTokenSource((*oauth2.Token)(token), v)
|
||||
return oauth.RefreshTokenSource((*oauth2.Token)(token), v.refreshToken)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue