From dbb8902456b61896ec503d2217c3899d5d8b8860 Mon Sep 17 00:00:00 2001 From: ms-jahan Date: Wed, 26 May 2021 21:52:20 +0600 Subject: [PATCH 1/6] Fixed some login issues and others --- fbchat/_client.py | 12 ++++++++---- fbchat/_state.py | 22 +++++++++++++++++++--- fbchat/_util.py | 10 ++-------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/fbchat/_client.py b/fbchat/_client.py index 30279449..8047d038 100644 --- a/fbchat/_client.py +++ b/fbchat/_client.py @@ -2614,14 +2614,18 @@ def getThreadIdAndThreadType(msg_metadata): thread_id, thread_type = getThreadIdAndThreadType(i) mid = i["messageId"] author_id = str(i["userId"]) - reaction = ( - MessageReaction(i["reaction"]) if i.get("reaction") else None - ) + + # Commented as the statement below invalidates other reaction emoji + + # reaction = (reaction = ( + # MessageReaction(i["reaction"]) if i.get("reaction") else None + # ) + add_reaction = not bool(i["action"]) if add_reaction: self.onReactionAdded( mid=mid, - reaction=reaction, + reaction=i.get("reaction"), author_id=author_id, thread_id=thread_id, thread_type=thread_type, diff --git a/fbchat/_state.py b/fbchat/_state.py index 3aebcecf..9f08e1cc 100644 --- a/fbchat/_state.py +++ b/fbchat/_state.py @@ -15,6 +15,9 @@ def get_user_id(session): # TODO: Optimize this `.get_dict()` call! rtn = session.cookies.get_dict().get("c_user") + # Sometimes c_user is missing if logged in from another location + if rtn is None: + rtn = str(input("c_user is blank, enter manually from browser cookies: ")) if rtn is None: raise _exception.FBchatException("Could not find user id") return str(rtn) @@ -147,6 +150,10 @@ def login(cls, email, password, on_2fa_callback, user_agent=None): if "save-device" in r.url: r = session.get("https://m.facebook.com/login/save-device/cancel/") + # Sometimes facebook redirects to facebook.com/cookie/consent-page/*[...more directories]. So, go to homepage + if "cookie" in r.url: + r = session.get("https://m.facebook.com/", allow_redirects=False) + if is_home(r.url): return cls.from_session(session=session) else: @@ -177,7 +184,6 @@ def from_session(cls, session): user_id = get_user_id(session) r = session.get(_util.prefix_url("/")) - soup = find_input_fields(r.text) fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"}) @@ -185,9 +191,19 @@ def from_session(cls, session): fb_dtsg = fb_dtsg_element["value"] else: # Fall back to searching with a regex + fb_dtsg = '' fb_dtsg = FB_DTSG_REGEX.search(r.text).group(1) - - revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0]) + + if fb_dtsg == "": + FB_DTSG_REGEX = re.compile(r'"name":"fb_dtsg","value":"(.*?)"') + + if fb_dtsg == '': + FB_DTSG_REGEX = re.compile(r'"[a-zA-Z0-9_.-]*:[a-zA-Z0-9_.-]*"\)') # I'm not good at regex + fb_dtsg = FB_DTSG_REGEX.search(r.text).group(0) + fb_dtsg = fb_dtsg.replace(")", "") + fb_dtsg = fb_dtsg.replace('"', '') + + revision = int(r.text.split('"client_revision":')[1].split(",", 1)[0]) logout_h_element = soup.find("input", {"name": "h"}) logout_h = logout_h_element["value"] if logout_h_element else None diff --git a/fbchat/_util.py b/fbchat/_util.py index 920e3749..fd6da1ab 100644 --- a/fbchat/_util.py +++ b/fbchat/_util.py @@ -43,14 +43,8 @@ log.addHandler(handler) #: Default list of user agents -USER_AGENTS = [ - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/601.1.10 (KHTML, like Gecko) Version/8.0.5 Safari/601.1.10", - "Mozilla/5.0 (Windows NT 6.3; WOW64; ; NCT50_AAP285C84A1328) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", - "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", -] +# Changing to this user-agent solved login issue for some people. +USER_AGENTS = ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36"] def now(): From ae4713e829f49dd70ab3c4343e3cf3f453804356 Mon Sep 17 00:00:00 2001 From: ms-jahan Date: Fri, 28 May 2021 21:34:46 +0600 Subject: [PATCH 2/6] Fix for previous commit --- fbchat/_state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fbchat/_state.py b/fbchat/_state.py index 9f08e1cc..aff35e71 100644 --- a/fbchat/_state.py +++ b/fbchat/_state.py @@ -196,6 +196,7 @@ def from_session(cls, session): if fb_dtsg == "": FB_DTSG_REGEX = re.compile(r'"name":"fb_dtsg","value":"(.*?)"') + fb_dtsg = FB_DTSG_REGEX.search(r.text).group(1) if fb_dtsg == '': FB_DTSG_REGEX = re.compile(r'"[a-zA-Z0-9_.-]*:[a-zA-Z0-9_.-]*"\)') # I'm not good at regex From 5046593dab0ed73ddb1fa3d565d59e94b1f5b38d Mon Sep 17 00:00:00 2001 From: "Md. Sarwar Jahan Sabit" Date: Sun, 30 May 2021 15:37:34 +0600 Subject: [PATCH 3/6] Update _client.py Removed restriction for reaction --- fbchat/_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbchat/_client.py b/fbchat/_client.py index 8047d038..77665a40 100644 --- a/fbchat/_client.py +++ b/fbchat/_client.py @@ -1714,7 +1714,7 @@ def reactToMessage(self, message_id, reaction): "client_mutation_id": "1", "actor_id": self._uid, "message_id": str(message_id), - "reaction": reaction.value if reaction else None, + "reaction": reaction if reaction else None } data = {"doc_id": 1491398900900362, "variables": json.dumps({"data": data})} j = self._payload_post("/webgraphql/mutation", data) From 6e23ca664450af26d193328b677e1f3a0b15ba92 Mon Sep 17 00:00:00 2001 From: ms-jahan Date: Sat, 17 Jul 2021 10:55:57 +0600 Subject: [PATCH 4/6] [fb_dtsg] patch --- fbchat/_state.py | 49 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/fbchat/_state.py b/fbchat/_state.py index aff35e71..3bce44ff 100644 --- a/fbchat/_state.py +++ b/fbchat/_state.py @@ -186,23 +186,44 @@ def from_session(cls, session): r = session.get(_util.prefix_url("/")) soup = find_input_fields(r.text) - fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"}) - if fb_dtsg_element: - fb_dtsg = fb_dtsg_element["value"] - else: + fb_dtsg = '' + + if fb_dtsg == None or fb_dtsg == "": + FB_DTSG_REGEX = re.compile(r'"[a-zA-Z0-9-_:]+:+[a-zA-Z0-9-_:]*"') + fb_dtsg = FB_DTSG_REGEX.search(r.text).group(0) + fb_dtsg = fb_dtsg.replace('"', "") + fb_dtsg = fb_dtsg.replace("'", '') + # print("\n\n[latest] fb_dtsg:\n") + # print(fb_dtsg) + + + if fb_dtsg == None or fb_dtsg == "": + fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"}) + print("\n\n[1]fb_dtsg_element:\n") + print(fb_dtsg_element) + if fb_dtsg_element: + fb_dtsg = fb_dtsg_element["value"] + # print("\n\n[1.1]fb_dtsg_element:\n") + # print(fb_dtsg) + + if fb_dtsg == None or fb_dtsg == "": # Fall back to searching with a regex fb_dtsg = '' - fb_dtsg = FB_DTSG_REGEX.search(r.text).group(1) - - if fb_dtsg == "": - FB_DTSG_REGEX = re.compile(r'"name":"fb_dtsg","value":"(.*?)"') + try: fb_dtsg = FB_DTSG_REGEX.search(r.text).group(1) - - if fb_dtsg == '': - FB_DTSG_REGEX = re.compile(r'"[a-zA-Z0-9_.-]*:[a-zA-Z0-9_.-]*"\)') # I'm not good at regex - fb_dtsg = FB_DTSG_REGEX.search(r.text).group(0) - fb_dtsg = fb_dtsg.replace(")", "") - fb_dtsg = fb_dtsg.replace('"', '') + # print("\n\n[2]fb_dtsg_element:\n") + # print(fb_dtsg) + except: + pass + + + if fb_dtsg == None or fb_dtsg == "": + FB_DTSG_REGEX = re.compile(r'"[a-zA-Z0-9_.-]*:[a-zA-Z0-9_.-]*"\)') + fb_dtsg = FB_DTSG_REGEX.search(r.text).group(0) + fb_dtsg = fb_dtsg.replace(")", "") + fb_dtsg = fb_dtsg.replace('"', '') + # print("\n\n[3]fb_dtsg_element:\n") + # print(fb_dtsg) revision = int(r.text.split('"client_revision":')[1].split(",", 1)[0]) From 5d04f8d60b4d252fefc99aa550d932f8c37b0db4 Mon Sep 17 00:00:00 2001 From: "Md. Sarwar Jahan Sabit" Date: Sun, 29 May 2022 16:10:41 +0600 Subject: [PATCH 5/6] Updated login issue Removed session headers and (I don't know why) the problem is solved --- fbchat/_client.py | 2 +- fbchat/_state.py | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fbchat/_client.py b/fbchat/_client.py index 77665a40..af6d36c6 100644 --- a/fbchat/_client.py +++ b/fbchat/_client.py @@ -68,7 +68,7 @@ def __init__( self, email, password, - user_agent=None, + user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36", max_tries=5, session_cookies=None, logging_level=logging.INFO, diff --git a/fbchat/_state.py b/fbchat/_state.py index 3bce44ff..52fb1833 100644 --- a/fbchat/_state.py +++ b/fbchat/_state.py @@ -1,5 +1,6 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +from pprint import pprint import attr import bs4 @@ -24,16 +25,17 @@ def get_user_id(session): def find_input_fields(html): - return bs4.BeautifulSoup(html, "html.parser", parse_only=bs4.SoupStrainer("input")) + # return bs4.BeautifulSoup(html, "html.parser", parse_only=bs4.SoupStrainer("input")) + return bs4.BeautifulSoup(html, "html.parser") def session_factory(user_agent=None): - session = requests.session() - session.headers["Referer"] = "https://www.facebook.com" - session.headers["Accept"] = "text/html" + session = requests.Session() + # session.headers["Referer"] = "https://www.facebook.com" + # session.headers["Accept"] = "text/html" # TODO: Deprecate setting the user agent manually - session.headers["User-Agent"] = user_agent or random.choice(_util.USER_AGENTS) + # session.headers["User-Agent"] = user_agent or random.choice(_util.USER_AGENTS) return session @@ -126,20 +128,29 @@ def get_params(self): } @classmethod - def login(cls, email, password, on_2fa_callback, user_agent=None): + def login(cls, email, password, on_2fa_callback, user_agent=_util.USER_AGENTS): session = session_factory(user_agent=user_agent) soup = find_input_fields(session.get("https://m.facebook.com/").text) + + soup = soup.find_all("input") + data = dict( (elem["name"], elem["value"]) for elem in soup if elem.has_attr("value") and elem.has_attr("name") ) + data["email"] = email data["pass"] = password data["login"] = "Log In" - r = session.post("https://m.facebook.com/login.php?login_attempt=1", data=data) + # pprint(data) + r = session.post("https://m.facebook.com/login/device-based/regular/login/?refsrc=deprecated&lwv=100&refid=8", data=data) + + # print(r.status_code) + # print(r.url) + # print(r.content) # Usually, 'Checkpoint' will refer to 2FA if "checkpoint" in r.url and ('id="approvals_code"' in r.text.lower()): @@ -229,6 +240,8 @@ def from_session(cls, session): logout_h_element = soup.find("input", {"name": "h"}) logout_h = logout_h_element["value"] if logout_h_element else None + + print(user_id, fb_dtsg, revision, logout_h) return cls( user_id=user_id, From b56e7a7575ba568f796a2070d2f526c591e04ac5 Mon Sep 17 00:00:00 2001 From: Jarek <42780718+jarekt@users.noreply.github.com> Date: Fri, 17 Jun 2022 23:03:31 +0200 Subject: [PATCH 6/6] fix first thread being skipped --- fbchat/_client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fbchat/_client.py b/fbchat/_client.py index af6d36c6..3e9c853d 100644 --- a/fbchat/_client.py +++ b/fbchat/_client.py @@ -312,7 +312,9 @@ def fetchThreads(self, thread_location, before=None, after=None, limit=None): before=last_thread_timestamp, thread_location=thread_location ) - if len(candidates) > 1: + if last_thread_timestamp == None and len(candidates) >= 1: + threads += candidates + elif len(candidates) > 1: threads += candidates[1:] else: # End of threads break