Skip to content

Commit

Permalink
Merge pull request coddingtonbear#129 from hannahburkhardt/128_fix_lo…
Browse files Browse the repository at this point in the history
…gin_flow

128 fix login flow
  • Loading branch information
coddingtonbear committed Dec 17, 2021
2 parents 3329122 + 31c0ea5 commit 3a4d2f8
Showing 1 changed file with 22 additions and 18 deletions.
40 changes: 22 additions & 18 deletions myfitnesspal/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import datetime
import json
import logging
import re
from collections import OrderedDict
Expand Down Expand Up @@ -32,7 +33,9 @@ class Client(MFPBase):
BASE_URL = "http:https://www.myfitnesspal.com/"
BASE_URL_SECURE = "https://www.myfitnesspal.com/"
BASE_API_URL = "https://api.myfitnesspal.com/"
LOGIN_PATH = "account/login"
LOGIN_FORM_PATH = "account/login"
LOGIN_JSON_PATH = "api/auth/callback/credentials"
CSRF_PATH = "api/auth/csrf"
SEARCH_PATH = "food/search"
ABBREVIATIONS = {
"carbs": "carbohydrates",
Expand Down Expand Up @@ -99,34 +102,27 @@ def effective_username(self) -> str:
return self.provided_username

def _login(self):
login_url = parse.urljoin(self.BASE_URL_SECURE, self.LOGIN_PATH)
document = self._get_document_for_url(login_url)
authenticity_token = document.xpath(
"(//input[@name='authenticity_token']/@value)[1]"
)[0]
utf8_field = document.xpath("(//input[@name='utf8']/@value)[1]")[0]
csrf_url = parse.urljoin(self.BASE_URL_SECURE, self.CSRF_PATH)
csrf_token = self._get_json_for_url(csrf_url)['csrfToken']

login_json_url = parse.urljoin(self.BASE_URL_SECURE, self.LOGIN_JSON_PATH)

result = self.session.post(
login_url,
login_json_url,
data={
"utf8": utf8_field,
"authenticity_token": authenticity_token,
"csrfToken": csrf_token,
"username": self.effective_username,
"password": self.__password,
"redirect": False,
"json": True,
},
)
# result.content is bytes so we decode it ASSUMING utf8 (which may be a
# bad assumption?) PORTING_CHECK
content = result.content.decode("utf8")
if "Incorrect username or password" in content:
if "error=CredentialsSignin" in result.url:
raise MyfitnesspalLoginError()

self._auth_data = self._get_auth_data()
self._user_metadata = self._get_user_metadata()

# authenticity token required for measurement set function.
self._authenticity_token = authenticity_token

def _get_auth_data(self) -> types.AuthData:
result = self._get_request_for_url(
parse.urljoin(self.BASE_URL_SECURE, "/user/auth_token") + "?refresh=true"
Expand Down Expand Up @@ -226,6 +222,11 @@ def _get_document_for_url(self, url):

return lxml.html.document_fromstring(content)

def _get_json_for_url(self, url):
content = self._get_content_for_url(url)

return json.loads(content)

def _get_measurement(self, name: str, value: Optional[float]) -> MeasureBase:
if not self.unit_aware:
return value
Expand Down Expand Up @@ -578,6 +579,9 @@ def set_measurements(
# the 'measurement' name to set the value.
document = self._get_document_for_url(self._get_url_for_measurements())

# get authenticity token for this particular form.
authenticity_token = document.xpath("//form[@action='/measurements/new']/input[@name='authenticity_token']/@value")[0]

# gather the IDs for all measurement types
measurement_ids = self._get_measurement_ids(document)

Expand All @@ -590,7 +594,7 @@ def set_measurements(

# setup a dict for the post
data = {
"authenticity_token": self._authenticity_token,
"authenticity_token": authenticity_token,
"measurement[display_value]": value,
"type": measurement_ids.get(measurement),
"measurement[entry_date(2i)]": date.month,
Expand Down

0 comments on commit 3a4d2f8

Please sign in to comment.