Skip to content

Commit

Permalink
Fix for login page, prepare 0.35.1 release
Browse files Browse the repository at this point in the history
  • Loading branch information
tillsteinbach committed Jan 28, 2022
1 parent 872934d commit 11c6076
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 28 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
- No unreleased changes so far

## [0.35.1] - 2022-01-28
### Fixed
- Quick fix for login problem due to changes of the login page

## [0.35.0] - 2022-01-24
### Changed
- Better tracking of several parallel requests
Expand Down Expand Up @@ -469,7 +473,8 @@ Minor fix in observer interface
## [0.1.0] - 2021-05-26
Initial release

[unreleased]: https://github.com/tillsteinbach/WeConnect-python/compare/v0.35.0...HEAD
[unreleased]: https://github.com/tillsteinbach/WeConnect-python/compare/v0.35.1...HEAD
[0.35.1]: https://github.com/tillsteinbach/WeConnect-python/releases/tag/v0.35.1
[0.35.0]: https://github.com/tillsteinbach/WeConnect-python/releases/tag/v0.35.0
[0.34.0]: https://github.com/tillsteinbach/WeConnect-python/releases/tag/v0.34.0
[0.33.0]: https://github.com/tillsteinbach/WeConnect-python/releases/tag/v0.33.0
Expand Down
53 changes: 26 additions & 27 deletions weconnect/weconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,45 +365,44 @@ def login(self) -> None: # noqa: C901 # pylint: disable=R0914, R0912, too-many-
# Post form content and retrieve credentials page
login2Response: requests.Response = self.__session.post(login2Url, headers=loginHeadersForm, data=formData, allow_redirects=True,
timeout=self.timeout)

if login2Response.status_code != requests.codes['ok']: # pylint: disable=E1101
if login2Response.status_code == requests.codes['internal_server_error']:
raise RetrievalError('Temporary server error during login')
raise APICompatibilityError('Retrieving credentials page was not successfull,'
f' status code: {login2Response.status_code}')

# Find credentials form on page to obtain inputs
credentialsFormRegex = r'<form.+id=\"credentialsForm\".*action=\"(?P<formAction>[^\"]+)\"[^>]*>' \
r'(?P<formContent>.+?(?=</form>))</form>'
match = re.search(credentialsFormRegex, login2Response.text, flags=re.DOTALL)
credentialsTemplateRegex = r'<script>\s+window\._IDK\s+=\s+\{\s' \
r'(?P<templateModel>.+?(?=\s+\};\s+</script>))\s+\};\s+</script>'
match = re.search(credentialsTemplateRegex, login2Response.text, flags=re.DOTALL)
if match is None:
formErrorRegex = r'<div.+class=\".*error\">.*<span\sclass=\"message\">' \
r'(?P<errorMessage>.+?(?=</span>))</span>.*</div>'
errorMatch: Optional[Match[str]] = re.search(formErrorRegex, login2Response.text, flags=re.DOTALL)
if errorMatch is not None:
raise AuthentificationError(errorMatch.groupdict()['errorMessage'])

accountNotFoundRegex = r'<div\sid=\"title\"\sclass=\"title\">.*<div class=\"sub-title\">.*<div>' \
r'(?P<errorMessage>.+?(?=</div>))</div>.*</div>.*</div>'
errorMatch = re.search(accountNotFoundRegex, login2Response.text, flags=re.DOTALL)
if errorMatch is not None:
errorMessage: str = re.sub('<[^<]+?>', '', errorMatch.groupdict()['errorMessage'])
raise AuthentificationError(errorMessage)
raise APICompatibilityError('No credentials form found')
# retrieve target url from form
target = match.groupdict()['formAction']

# Find all inputs and put those in formData dictionary
input2Regex = r'<input[\\n\\r\s][^/]*name=\"(?P<name>[^\"]+)\"([\\n\\r\s]value=\"(?P<value>[^\"]+)\")?[^/]*/>'
form2Data: Dict[str, str] = {}
for match in re.finditer(input2Regex, match.groupdict()['formContent']):
if match.groupdict()['name']:
form2Data[match.groupdict()['name']] = match.groupdict()['value']
if match.groupdict()['templateModel']:
lineRegex = r'\s*(?P<name>[^\:]+)\:\s+[\'\{]?(?P<value>.+)[\'\}][,]?'
form2Data: Dict[str, str] = {}
for match in re.finditer(lineRegex, match.groupdict()['templateModel']):
if match.groupdict()['name'] == 'templateModel':
templateModelString = '{' + match.groupdict()['value'] + '}'
if templateModelString.endswith(','):
templateModelString = templateModelString[:-len(',')]
templateModel = json.loads(templateModelString)
if 'relayState' in templateModel:
form2Data['relayState'] = templateModel['relayState']
if 'hmac' in templateModel:
form2Data['hmac'] = templateModel['hmac']
if 'emailPasswordForm' in templateModel and 'email' in templateModel['emailPasswordForm']:
form2Data['email'] = templateModel['emailPasswordForm']['email']
if 'errorCode' in templateModel:
raise AuthentificationError('Error during login, is the username correct?')
elif match.groupdict()['name'] == 'csrf_token':
form2Data['_csrf'] = match.groupdict()['value']
form2Data['password'] = self.password
if not all(x in ['_csrf', 'relayState', 'hmac', 'email', 'password'] for x in form2Data):
raise APICompatibilityError('Could not find all required input fields in login page')
form2Data['password'] = self.password

# build url from form action
login3Url: str = 'https://identity.vwgroup.io' + target
# TODO improve build url from form action
login3Url = 'https://identity.vwgroup.io/signin-service/v1/a24fba63-34b3-4d43-b181-942111e6bda8@apps_vw-dilab_com/login/authenticate'

# Post form content and retrieve userId in forwarding Location
login3Response: requests.Response = self.__session.post(login3Url, headers=loginHeadersForm, data=form2Data, allow_redirects=False,
Expand Down

0 comments on commit 11c6076

Please sign in to comment.