Refactor session cookie handling into State

This commit is contained in:
Mads Marquart
2019-06-26 20:03:38 +02:00
parent 94a0f6b3df
commit b01b371c66
2 changed files with 35 additions and 22 deletions

View File

@@ -115,8 +115,8 @@ class Client(object):
It may be a bad idea to do this in an exception handler, if you have a better method, please suggest it! It may be a bad idea to do this in an exception handler, if you have a better method, please suggest it!
""" """
if error_code == "1357004": if error_code == "1357004":
log.warning("Got error #1357004. Doing a _postLogin, and resending request") log.warning("Got error #1357004. Refreshing state and resending request")
self._postLogin() self._state = State.from_session(session=self._state._session)
return True return True
return False return False
@@ -263,15 +263,6 @@ class Client(object):
self._uid = None self._uid = None
self._client_id = hex(int(random() * 2147483648))[2:] self._client_id = hex(int(random() * 2147483648))[2:]
def _postLogin(self):
self._uid = self._state._session.cookies.get_dict().get("c_user")
if self._uid is None:
raise FBchatException("Could not find c_user cookie")
self._uid = str(self._uid)
r = self._get("/")
self._state = State.from_base_request(self._state._session, r.text)
def _login(self, email, password): def _login(self, email, password):
soup = bs(self._get("https://m.facebook.com/").text, "html.parser") soup = bs(self._get("https://m.facebook.com/").text, "html.parser")
data = dict( data = dict(
@@ -294,7 +285,10 @@ class Client(object):
r = self._get("https://m.facebook.com/login/save-device/cancel/") r = self._get("https://m.facebook.com/login/save-device/cancel/")
if "home" in r.url: if "home" in r.url:
self._postLogin() self._state = State.from_session(session=self._state._session)
self._uid = self._state.get_user_id()
if self._uid is None:
raise FBchatException("Could not find c_user cookie")
return True, r.url return True, r.url
else: else:
return False, r.url return False, r.url
@@ -378,7 +372,7 @@ class Client(object):
:return: A dictionay containing session cookies :return: A dictionay containing session cookies
:rtype: dict :rtype: dict
""" """
return self._state._session.cookies.get_dict() return self._state.get_cookies()
def setSession(self, session_cookies): def setSession(self, session_cookies):
"""Loads session cookies """Loads session cookies
@@ -394,14 +388,16 @@ class Client(object):
try: try:
# Load cookies into current session # Load cookies into current session
self._state._session.cookies = requests.cookies.merge_cookies( self._state = State.from_cookies(session_cookies)
self._state._session.cookies, session_cookies
)
self._postLogin()
except Exception as e: except Exception as e:
log.exception("Failed loading session") log.exception("Failed loading session")
self._resetValues() self._state = State()
return False return False
uid = self._state.get_user_id()
if uid is None:
log.warning("Could not find c_user cookie")
return False
self._uid = uid
return True return True
def login(self, email, password, max_tries=5): def login(self, email, password, max_tries=5):

View File

@@ -21,6 +21,12 @@ class State(object):
_counter = attr.ib(0) _counter = attr.ib(0)
_logout_h = attr.ib(None) _logout_h = attr.ib(None)
def get_user_id(self):
rtn = self.get_cookies().get("c_user")
if rtn is None:
return None
return str(rtn)
@property @property
def logout_h(self): def logout_h(self):
return self._logout_h return self._logout_h
@@ -37,17 +43,19 @@ class State(object):
} }
@classmethod @classmethod
def from_base_request(cls, session, content): def from_session(cls, session):
soup = bs4.BeautifulSoup(content, "html.parser") r = session.get(_util.prefix_url("/"))
soup = bs4.BeautifulSoup(r.text, "html.parser")
fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"}) fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"})
if fb_dtsg_element: if fb_dtsg_element:
fb_dtsg = fb_dtsg_element["value"] fb_dtsg = fb_dtsg_element["value"]
else: else:
# Fall back to searching with a regex # Fall back to searching with a regex
fb_dtsg = FB_DTSG_REGEX.search(content).group(1) fb_dtsg = FB_DTSG_REGEX.search(r.text).group(1)
revision = int(content.split('"client_revision":', 1)[1].split(",", 1)[0]) revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0])
logout_h_element = soup.find("input", {"name": "h"}) logout_h_element = soup.find("input", {"name": "h"})
logout_h = logout_h_element["value"] if logout_h_element else None logout_h = logout_h_element["value"] if logout_h_element else None
@@ -55,3 +63,12 @@ class State(object):
return cls( return cls(
session=session, fb_dtsg=fb_dtsg, revision=revision, logout_h=logout_h session=session, fb_dtsg=fb_dtsg, revision=revision, logout_h=logout_h
) )
def get_cookies(self):
return self._session.cookies.get_dict()
@classmethod
def from_cookies(cls, cookies):
session = requests.session()
session.cookies = requests.cookies.merge_cookies(session.cookies, cookies)
return cls.from_session(session=session)