BMW/Mini: add hcaptcha (#17445)
This commit is contained in:
parent
d7e87bf207
commit
9754bb91c8
4 changed files with 58 additions and 5 deletions
|
|
@ -1,6 +1,12 @@
|
|||
template: bmw
|
||||
products:
|
||||
- brand: BMW
|
||||
requirements:
|
||||
description:
|
||||
de: |
|
||||
Benötigt `hcaptcha` Token. Dieses muss einmalig unter https://bimmer-connected.readthedocs.io/en/latest/captcha/rest_of_world.html generiert werden. Das Token ist nur für kurze Zeit gültig. Bitte möglichst schnell nach Generierung in die Konfiguration kopieren und evcc starten.
|
||||
en: |
|
||||
Requires `hcaptcha` token. This must be generated once at https://bimmer-connected.readthedocs.io/en/latest/captcha/rest_of_world.html. The token is only valid for a short time. Please copy it into the configuration and start evcc as soon as possible after generation.
|
||||
params:
|
||||
- preset: vehicle-base
|
||||
- preset: vehicle-identify
|
||||
|
|
@ -19,6 +25,8 @@ params:
|
|||
advanced: true
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
- name: hcaptcha
|
||||
required: true
|
||||
render: |
|
||||
type: bmw
|
||||
{{ include "vehicle-base" . }}
|
||||
|
|
@ -35,3 +43,4 @@ render: |
|
|||
- welcomecharge
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
hcaptcha: {{ .hcaptcha }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
template: mini
|
||||
products:
|
||||
- brand: Mini
|
||||
requirements:
|
||||
description:
|
||||
de: |
|
||||
Benötigt `hcaptcha` Token. Dieses muss einmalig unter https://bimmer-connected.readthedocs.io/en/latest/captcha/rest_of_world.html generiert werden. Das Token ist nur für kurze Zeit gültig. Bitte möglichst schnell nach Generierung in die Konfiguration kopieren und evcc starten.
|
||||
en: |
|
||||
Requires `hcaptcha` token. This must be generated once at https://bimmer-connected.readthedocs.io/en/latest/captcha/rest_of_world.html. The token is only valid for a short time. Please copy it into the configuration and start evcc as soon as possible after generation.
|
||||
params:
|
||||
- preset: vehicle-base
|
||||
- preset: vehicle-identify
|
||||
|
|
@ -17,6 +23,8 @@ params:
|
|||
advanced: true
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
- name: hcaptcha
|
||||
required: true
|
||||
render: |
|
||||
type: mini
|
||||
{{ include "vehicle-base" . }}
|
||||
|
|
@ -27,3 +35,4 @@ render: |
|
|||
{{- if eq .welcomecharge "true" }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
hcaptcha: {{ .hcaptcha }}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ func NewBMWMiniFromConfig(brand string, other map[string]interface{}) (api.Vehic
|
|||
cc := struct {
|
||||
embed `mapstructure:",squash"`
|
||||
User, Password, VIN string
|
||||
Hcaptcha string
|
||||
Region string
|
||||
Cache time.Duration
|
||||
}{
|
||||
|
|
@ -45,7 +46,7 @@ func NewBMWMiniFromConfig(brand string, other map[string]interface{}) (api.Vehic
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if cc.User == "" || cc.Password == "" {
|
||||
if cc.User == "" || cc.Password == "" || cc.Hcaptcha == "" {
|
||||
return nil, api.ErrMissingCredentials
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ func NewBMWMiniFromConfig(brand string, other map[string]interface{}) (api.Vehic
|
|||
log := util.NewLogger(brand).Redact(cc.User, cc.Password, cc.VIN)
|
||||
identity := bmw.NewIdentity(log, cc.Region)
|
||||
|
||||
ts, err := identity.Login(cc.User, cc.Password)
|
||||
ts, err := identity.Login(cc.User, cc.Password, cc.Hcaptcha)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/server/db/settings"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/oauth"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -23,6 +24,8 @@ const (
|
|||
type Identity struct {
|
||||
*request.Helper
|
||||
region Region
|
||||
log *util.Logger
|
||||
user string
|
||||
}
|
||||
|
||||
// NewIdentity creates BMW identity
|
||||
|
|
@ -30,15 +33,32 @@ func NewIdentity(log *util.Logger, region string) *Identity {
|
|||
v := &Identity{
|
||||
Helper: request.NewHelper(log),
|
||||
region: regions[strings.ToUpper(region)],
|
||||
log: log,
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Identity) Login(user, password string) (oauth2.TokenSource, error) {
|
||||
func (v *Identity) Login(user, password, hcaptcha string) (oauth2.TokenSource, error) {
|
||||
v.Client.CheckRedirect = request.DontFollow
|
||||
defer func() { v.Client.CheckRedirect = nil }()
|
||||
|
||||
v.user = user
|
||||
|
||||
// database token
|
||||
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)
|
||||
if err == nil {
|
||||
ts := oauth2.ReuseTokenSourceWithExpiry(tok, oauth.RefreshTokenSource(tok, v), 15*time.Minute)
|
||||
return ts, nil
|
||||
}
|
||||
v.log.DEBUG.Println("identity.Login - database token invalid. Proceeding to login via user, password and captcha.")
|
||||
} else {
|
||||
v.log.DEBUG.Println("identity.Login - no database token found. Proceeding to login via user, password and captcha.")
|
||||
}
|
||||
|
||||
cv := oauth2.GenerateVerifier()
|
||||
|
||||
v.Jar, _ = cookiejar.New(&cookiejar.Options{
|
||||
|
|
@ -60,7 +80,11 @@ func (v *Identity) Login(user, password string) (oauth2.TokenSource, error) {
|
|||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/oauth/authenticate", v.region.AuthURI)
|
||||
req, err := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), request.URLEncoding)
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"hcaptchatoken": hcaptcha,
|
||||
}
|
||||
req, err := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -141,9 +165,15 @@ func (v *Identity) retrieveToken(data url.Values) (*oauth2.Token, error) {
|
|||
var tok oauth2.Token
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, &tok)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return util.TokenWithExpiry(&tok), err
|
||||
tokex := util.TokenWithExpiry(&tok)
|
||||
|
||||
err = settings.SetJson(v.settingsKey(), tokex)
|
||||
|
||||
return tokex, err
|
||||
}
|
||||
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
|
|
@ -155,3 +185,7 @@ func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
|||
|
||||
return v.retrieveToken(data)
|
||||
}
|
||||
|
||||
func (v *Identity) settingsKey() string {
|
||||
return fmt.Sprintf("bmw.%s", v.user)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue