2024-07-19 07:05:27 +00:00
|
|
|
"""Application Credentials platform the Tesla Fleet integration."""
|
|
|
|
|
|
|
|
import base64
|
|
|
|
import hashlib
|
|
|
|
import secrets
|
|
|
|
from typing import Any
|
|
|
|
|
2024-08-07 11:11:03 +00:00
|
|
|
from homeassistant.components.application_credentials import (
|
|
|
|
AuthImplementation,
|
|
|
|
AuthorizationServer,
|
|
|
|
ClientCredential,
|
|
|
|
)
|
2024-07-19 07:05:27 +00:00
|
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from homeassistant.helpers import config_entry_oauth2_flow
|
|
|
|
|
2024-08-07 11:11:03 +00:00
|
|
|
from .const import AUTHORIZE_URL, DOMAIN, SCOPES, TOKEN_URL
|
2024-07-19 07:05:27 +00:00
|
|
|
|
2024-08-07 11:11:03 +00:00
|
|
|
AUTH_SERVER = AuthorizationServer(AUTHORIZE_URL, TOKEN_URL)
|
2024-07-19 07:05:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def async_get_auth_implementation(
|
|
|
|
hass: HomeAssistant, auth_domain: str, credential: ClientCredential
|
|
|
|
) -> config_entry_oauth2_flow.AbstractOAuth2Implementation:
|
|
|
|
"""Return auth implementation."""
|
|
|
|
return TeslaOAuth2Implementation(
|
|
|
|
hass,
|
|
|
|
DOMAIN,
|
2024-08-07 11:11:03 +00:00
|
|
|
credential,
|
2024-07-19 07:05:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-08-07 11:11:03 +00:00
|
|
|
class TeslaOAuth2Implementation(AuthImplementation):
|
2024-07-19 07:05:27 +00:00
|
|
|
"""Tesla Fleet API Open Source Oauth2 implementation."""
|
|
|
|
|
2024-08-07 11:11:03 +00:00
|
|
|
def __init__(
|
|
|
|
self, hass: HomeAssistant, domain: str, credential: ClientCredential
|
|
|
|
) -> None:
|
2024-07-19 07:05:27 +00:00
|
|
|
"""Initialize local auth implementation."""
|
|
|
|
self.hass = hass
|
|
|
|
self._domain = domain
|
|
|
|
|
|
|
|
# Setup PKCE
|
|
|
|
self.code_verifier = secrets.token_urlsafe(32)
|
|
|
|
hashed_verifier = hashlib.sha256(self.code_verifier.encode()).digest()
|
|
|
|
self.code_challenge = (
|
|
|
|
base64.urlsafe_b64encode(hashed_verifier).decode().replace("=", "")
|
|
|
|
)
|
|
|
|
super().__init__(
|
|
|
|
hass,
|
|
|
|
domain,
|
2024-08-07 11:11:03 +00:00
|
|
|
credential,
|
|
|
|
AUTH_SERVER,
|
2024-07-19 07:05:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def extra_authorize_data(self) -> dict[str, Any]:
|
|
|
|
"""Extra data that needs to be appended to the authorize url."""
|
|
|
|
return {
|
|
|
|
"scope": " ".join(SCOPES),
|
|
|
|
"code_challenge": self.code_challenge, # PKCE
|
|
|
|
}
|
|
|
|
|
|
|
|
async def async_resolve_external_data(self, external_data: Any) -> dict:
|
|
|
|
"""Resolve the authorization code to tokens."""
|
|
|
|
return await self._token_request(
|
|
|
|
{
|
|
|
|
"grant_type": "authorization_code",
|
|
|
|
"code": external_data["code"],
|
|
|
|
"redirect_uri": external_data["state"]["redirect_uri"],
|
|
|
|
"code_verifier": self.code_verifier, # PKCE
|
|
|
|
}
|
|
|
|
)
|