1313import base64
1414import secrets
1515import string
16+ import re
1617
1718from jsonpath import jsonpath
18- from urllib import parse
1919from json .decoder import JSONDecodeError
2020
2121from .envoy_endpoints import (
2828ENVOY_MODEL_M = "Metered"
2929ENVOY_MODEL_S = "Standard"
3030
31- ENLIGHTEN_AUTH_URL = "https://enlighten.enphaseenergy.com/login/login.json?"
32- ENLIGHTEN_TOKEN_URL = "https://entrez.enphaseenergy.com/tokens"
33-
3431# paths used for fetching enlighten token through envoy
35- ENLIGHTEN_LOGIN_URL = "https://entrez.enphaseenergy.com/login"
36- ENDPOINT_URL_GET_JWT = "https://{}/auth/get_jwt "
32+ ENTREZ_LOGIN_URL = "https://entrez.enphaseenergy.com/login"
33+ ENTREZ_TOKEN_URL = "https://entrez.enphaseenergy.com/entrez_tokens "
3734ENDPOINT_URL_CHECK_JWT = "https://{}/auth/check_jwt"
3835
3936_LOGGER = logging .getLogger (__name__ )
@@ -787,7 +784,6 @@ def __init__(
787784 disabled_endpoints = [],
788785 lifetime_production_correction = 0 ,
789786 device_data_endpoint = "endpoint_device_data" ,
790- token_method_envoy = False ,
791787 ):
792788 """Init the EnvoyReader."""
793789 self .host = host .lower ()
@@ -813,7 +809,6 @@ def __init__(
813809 self .disabled_endpoints = disabled_endpoints
814810 self .lifetime_production_correction = lifetime_production_correction
815811 self .device_data_endpoint = device_data_endpoint
816- self .token_method_envoy = token_method_envoy
817812
818813 self .uri_registry = {}
819814 for key , endpoint in ENVOY_ENDPOINTS .items ():
@@ -975,109 +970,49 @@ async def _async_put(self, url, data, **kwargs):
975970 _LOGGER .debug ("TransportError: %s" , e )
976971 raise e
977972
978- async def _fetch_enlighten_token_json (self ):
973+ async def _fetch_entrez_token (self ):
979974 """
980- Try to fetch the token json from Enlighten API
975+ Try to fetch the token json from Entrez
981976 :return:
982977 """
983978 _LOGGER .debug ("Fetching enlighten token" )
984979 async with self .async_client as client :
985980 # login to Enlighten
986981 payload_login = {
987- "user[email] " : self .enlighten_user ,
988- "user[ password] " : self .enlighten_pass ,
982+ "username " : self .enlighten_user ,
983+ "password" : self .enlighten_pass ,
989984 }
990- resp = await client .post (ENLIGHTEN_AUTH_URL , data = payload_login , timeout = 30 )
991- if resp .status_code >= 400 :
985+ login_resp = await client .post (
986+ ENTREZ_LOGIN_URL , data = payload_login , timeout = 30
987+ )
988+ if login_resp .status_code >= 400 :
992989 raise EnlightenError ("Could not Authenticate via Enlighten" )
993990
994991 # now that we're in a logged in session, we can request the installer token
995- login_data = resp .json ()
996992 payload_token = {
997- "session_id" : login_data ["session_id" ],
998- "serial_num" : self .enlighten_serial_num ,
999- "username" : self .enlighten_user ,
993+ "serialNum" : self .enlighten_serial_num ,
1000994 }
1001- resp = await client .post (
1002- ENLIGHTEN_TOKEN_URL , json = payload_token , timeout = 30
995+ token_resp = await client .post (
996+ ENTREZ_TOKEN_URL ,
997+ data = payload_token ,
998+ timeout = 30 ,
999+ cookies = login_resp .cookies ,
10031000 )
1004- if resp .status_code != 200 :
1001+ if token_resp .status_code != 200 :
10051002 raise EnlightenError ("Could not get enlighten token" )
1006- return resp .text
10071003
1008- async def _fetch_envoy_token_json (self ):
1009- """
1010- Fetch a token, using the same procedure envoy uses in the webUI
1011-
1012- :returns received access_token
1013- """
1014- _LOGGER .debug ("Fetching envoy token" )
1015- async with self .async_client as client :
1016- # Step 1, generate local secret
1017- code_verifier = random_content (40 )
1018-
1019- _LOGGER .debug ("Local auth secret: %s" , code_verifier )
1020-
1021- # Step 2, call the entrez login with form fields
1022- # all params are reverse engineered, so prone to changes
1023- login_data = dict (
1024- username = self .enlighten_user ,
1025- password = self .enlighten_pass ,
1026- codeChallenge = generate_challenge (code_verifier ),
1027- redirectUri = f"https://{ self .host } /auth/callback" ,
1028- client = "envoy-ui" ,
1029- clientId = "envoy-ui-client" ,
1030- authFlow = "oauth" ,
1031- serialNum = self .enlighten_serial_num ,
1032- granttype = "authorize" ,
1033- state = "" ,
1034- invalidSerialNum = "" ,
1004+ match = re .search (
1005+ r"<textarea[^>]*>(.*?)</textarea>" , token_resp .text , re .DOTALL
10351006 )
1036- _LOGGER .debug (
1037- "Doing authorize at entrez, with codeChallenge: %s" ,
1038- login_data ["codeChallenge" ],
1039- )
1040- resp = await client .post (ENLIGHTEN_LOGIN_URL , data = login_data )
1041-
1042- if resp .status_code >= 400 :
1043- raise EnlightenError ("Could not Login via Enlighten" )
1044-
1045- # we should expect a 302 redirect
1046- if resp .status_code != 302 :
1047- raise EnlightenError ("Login did not succeed" )
1048-
1049- # Step 3: Fetch the code from the query params.
1050- redirect_location = resp .headers .get ("location" )
1051- url_parts = parse .urlparse (redirect_location )
1052- query_parts = parse .parse_qs (url_parts .query )
1053-
1054- # Step 4: Fetch the JWT token through envoy
1055- json_data = {
1056- "client_id" : "envoy-ui-1" ,
1057- "code" : query_parts ["code" ][0 ],
1058- "code_verifier" : code_verifier ,
1059- "grant_type" : "authorization_code" ,
1060- "redirect_uri" : login_data ["redirectUri" ],
1061- }
1062- _LOGGER .debug ("Checking JWT on envoy with params %s" , json_data )
1063- resp = await client .post (
1064- ENDPOINT_URL_GET_JWT .format (self .host ),
1065- json = json_data ,
1066- timeout = 30 ,
1067- )
1068-
1069- if resp .status_code != 200 :
1070- raise EnvoyError (
1071- f"Could not fetch access token from envoy; HTTP { resp .status_code } : { resp .text } "
1072- )
1007+ if match :
1008+ token = match .group (1 ).strip ()
1009+ else :
1010+ raise EnlightenError ("Could not get enlighten token" )
10731011
1074- return resp . json ()[ "access_token" ]
1012+ return token
10751013
10761014 async def _get_enphase_token (self ):
1077- if self .token_method_envoy :
1078- self ._token = await self ._fetch_envoy_token_json ()
1079- else :
1080- self ._token = await self ._fetch_enlighten_token_json ()
1015+ self ._token = await self ._fetch_entrez_token ()
10811016
10821017 _LOGGER .debug ("Envoy Token" )
10831018 if self ._is_enphase_token_expired (self ._token ):
0 commit comments