Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cant Login since morning! #638

Open
ambit0 opened this issue Mar 4, 2021 · 7 comments
Open

Cant Login since morning! #638

ambit0 opened this issue Mar 4, 2021 · 7 comments

Comments

@ambit0
Copy link

ambit0 commented Mar 4, 2021

I'm getting error:
fbchat._exception.FBchatUserError: Login failed. Check email/password. (Failed on url: https://m.facebook.com/cookie/consent-page/?next_uri=https%3A%2F%2Fm.facebook.com%2Fhome.php%3Frefsrc%3Dhttps%253A%252F%252Fwww.facebook.com%252F&_rdr)

@m-el-azzouzi
Copy link

m-el-azzouzi commented Mar 4, 2021

Check the location of the file _state.py (written in the Exception) then edit it and go to login function (around line 126), scroll to line: r = session.post("https://m.facebook.com/login.php?login_attempt=1", data=data) (line 139 for me).

Paste that after this line (with correct indentation):

if "cookie" in r.url:
    beg = r.text.find("action=")+8
    end = r.text.find("\"", beg)
    urlCookies = "https://m.facebook.com" + r.text[beg:end]
    payload = {i["name"]:i["value"] for i in find_input_fields(r.text).find_all('input')}
    r = session.post(urlCookies, data=payload)

@mawerty
Copy link

mawerty commented Mar 12, 2021

I used it, but now i have error:
Attempt #1 failed, retrying
Traceback (most recent call last):
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_client.py", line 205, in login
self._state = State.login(
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 157, in login
return cls.from_session(session=session)
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 196, in from_session
revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0])
IndexError: list index out of range

@m-el-azzouzi
Copy link

m-el-azzouzi commented Mar 12, 2021

I used it, but now i have error:
Attempt #1 failed, retrying
Traceback (most recent call last):
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_client.py", line 205, in login
self._state = State.login(
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 157, in login
return cls.from_session(session=session)
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 196, in from_session
revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0])
IndexError: list index out of range

Ok, do you have some more logs? It seems it's something with your config, not fbchat
Try print(r.text) before line 196 and paste what it prints

@mawerty
Copy link

mawerty commented Mar 13, 2021

Attempt #1 failed, retrying
Traceback (most recent call last):
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_client.py", line 205, in login
self._state = State.login(
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 157, in login
return cls.from_session(session=session)
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 196, in from_session
revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0])
IndexError: list index out of range

<title>Facebook</title><style type="text/css" nonce="Gqgqq8ec">/*tr>td,.b .bx>tbody>tr>td,.b .m td.bx{vertical-align:top;}.b .cp>tr>td,.b .cp>tbody>tr>td,.b .m td.cp{vertical-align:middle;}.b .m td{padding:0;}.b .m td.w{padding:2px;}.b .m td.dd{padding:4px;}.b .t{width:100%;}.b a,.b a:visited{color:#3b5998;text-decoration:none;}.b .bg,.b .bg:visited{color:#fff;}.b a:focus,.b a:hover{background-color:#3b5998;color:#fff;}.b .bg:focus,.b .bg:hover{background-color:#fff;color:#3b5998;}.ca{background:#eceff5;}.cb{-webkit-appearance:none;border:0;margin:0;padding:0;}.bb{-webkit-appearance:none;background:none;display:inline-block;font-size:12px;height:28px;line-height:28px;margin:0;overflow:visible;padding:0 9px;text-align:center;vertical-align:top;white-space:nowrap;}.b .bb{border-radius:2px;}.ci,a.ci,.b a.ci,.b a.ci:visited{background-color:#f5f6f7;color:#4b4f56;}.b a.ci:hover,.b .ci:hover{background-color:#ebedf0;color:#4b4f56;}.b .ci{border:1px solid #bec3c9;}.ci[disabled]{color:#bec3c9;}.b .ci[disabled]:hover{background-color:#f5f6f7;color:#bec3c9;}.bd,.gb,a.bd,a.gb,html .b a.bd,html .b a.gb{color:#fff;}.b .gb{background-color:#4080ff;border:1px solid #4476e8;}.b a.gb:hover,.b .gb:hover{background-color:#4580ef;}.b .bd{background-color:#4267b2;border:1px solid #365899;}.b a.bd:hover,.b .bd:hover{background-color:#465e91;}.bd[disabled]{color:#899bc1;}.gb[disabled]{color:#91b4fd;}.b .bd[disabled]:hover{background-color:#4267b2;}.b .gb[disabled]:hover{background-color:#4080ff;}.bb .dn{display:inline-block;}.b .bb .dn{display:inline-block;margin-top:0;vertical-align:middle;}.b a.bb::after{content:"";display:inline-block;height:100%;vertical-align:middle;}.bb .dn{line-height:20px;margin-top:4px;}.bb.fz{display:block;width:100%;}a.bb.fz,.b label.bb.fz{display:block;width:auto;}.b .bb{padding:0 8px;}.b a.bb{height:26px;line-height:26px;}.dn{pointer-events:none;}.dj{color:#90949c;}.eg{color:#4b4f56;}.de{color:#1d2129;}.di{font-size:12px;line-height:16px;}.fi{font-size:14px;line-height:20px;}.ba{font-weight:normal;}._52jh{font-weight:bold;}.bu{text-align:left;}.cj{display:inline-block;}.ck{width:100%;}.cm{color:gray;}.cl{font-size:small;}body,tr,input,textarea,.f{font-size:medium;}.cn{display:inline-block;}.cn .cv{display:block;font-size:small;white-space:normal;}.cr,.cs.s{cursor:pointer;display:block;}.b .cn a.cv,.cn .cv{color:#4b4f56;font-weight:bold;text-align:left;}.b .cn a.cv:hover,.b .cn a.cv:focus,.cn .cv:hover,.cn

.cv:focus{background:#4b4f56;color:#fff;}.b .cn a.cr:hover,.b .cn a.cr:focus,.cn .cr:hover,.cn .cr:focus{background:inherit;}.b .gq{padding:0;}.b .w{padding:2px;}.b .dd{padding:4px;}.s{border:0;display:inline-block;vertical-align:top;}i.s u{position:absolute;width:0;height:0;overflow:hidden;}.cu{-webkit-appearance:none;background-color:transparent;border:0;display:inline;font-size:inherit;margin:0;padding:0;}.cu:hover{background-color:#3b5998;color:#fff;white-space:normal;}.cw{color:#3b5998;}.bo{display:block;display:-webkit-box;max-width:100%;overflow:hidden;white-space:nowrap;}.bp{color:#4b4f56;font-size:12px;line-height:20px;white-space:nowrap;}.bq{background-color:#fff;border:0;display:inline-block;height:26px;line-height:26px;margin:0;padding-right:16px;position:relative;vertical-align:top;white-space:nowrap;}.bq input,.bq button,.bq .dn{color:#3b5998;}.bq a:hover,.bq a:hover .dn{color:#fff;}.bq.br,.bv.br{height:20px;line-height:20px;}.bv{-webkit-appearance:none;background-color:#fff;border:none;color:#4b4f56;display:inline-block;font-size:12px;height:26px;min-width:100%;padding:0;vertical-align:top;}.bq a.bv{color:#4b4f56;}a.bv .dn,a.bv .dn::before{display:inline-block;height:100%;margin-top:0;vertical-align:middle;}a.bv .dn::before{content:"";}.bt{background-color:#dadde1;}.bt .bv{background-color:#dadde1;}.bw{background-image:url(https://static.xx.fbcdn.net/rsrc.php/v3/yY/r/DEWLwbJ5Q9y.png);background-position:right center;background-repeat:no-repeat;bottom:0;display:block;pointer-events:none;position:absolute;right:0;top:0;width:16px;}.bt .bw{background-image:url(https://static.xx.fbcdn.net/rsrc.php/v3/yU/r/juEKbziydZc.png);}.gc{background:#ebedf0;border-top:1px solid #d0d1d5;font-size:small;padding:0 8px 4px;}.gd{border-bottom:1px solid #d0d1d5;margin:0 -8px 3px -8px;padding:8px;}.gd .gg{display:inline-block;margin:-1px -4px -1px -4px;padding:1px 4px 1px 4px;}.gg.gf{display:block;font-size:medium;font-weight:bold;}.ge{background:white;border:1px solid #bec3c9;display:block;margin-right:4px;padding:2px;}.b .gd .ge:hover{background:white;}.gg{display:block;font-size:small;margin-left:-4px;padding:3px 0 3px 4px;}.b a.gg,.b a.gg:visited{color:#1d2129;}.b a.gg:focus,.b a.gg:hover{background:#1d2129;color:#ebedf0;}.cy,.cy tr{font-size:small;}.dx{display:block;font-weight:bold;padding:6px 3px;text-align:center;}.b .dx{background-color:#f5f6f7;border:0;padding:4px;text-align:left;}.b .ds.ds{background:white;}.b .ds{border-bottom:1px solid #e5e5e5;}.b .cy.cy>:first-child{margin-top:-1px;}.cx{border-bottom:1px solid transparent;border-top:1px solid transparent;}.b .cx>{margin:6px;}.b .cx>:first-child{margin-top:5px;}.b .cx>:last-child{margin-bottom:5px;}.db{border-color:#ccced3 #c4c6ca #b4b6ba;border-style:solid;border-width:1px;}.dp{border-bottom:1px solid #e5e5e5;}.dv{display:block;font-size:small;}.dp:last-child{border-bottom:none;}.dt{height:16px;width:16px;}.dv .du{font-size:small;}.dq{background:#eceff5;}.dw{white-space:nowrap;}.b .dv:hover,.b .dv:focus{background:#d1e9ff;color:#3b5998;}.b .dv,.b .dv:visited,.b .dv:active{background:transparent;color:#1d2129;text-decoration:none;}.dr .dv,.dr .dv:visited,.dr .dv:active{margin:-2px -2px -2px -22px;min-height:16px;padding:2px 2px 2px 22px;}.df .dk .dl{font-size:x-small;height:auto;line-height:normal;margin-right:5px;padding-bottom:3px;padding-top:3px;}.df .dk .dl .dn{line-height:normal;}.do{white-space:nowrap;}.dg .dh{color:#365899;font-size:small;font-weight:bold;}.dh{font-size:14px;}.da>,.da.da>{border-bottom:1px solid #e5e5e5;}.da>:last-child{border-bottom:none;}.da+.da{border-top:1px solid #e5e5e5;}.b .ga{border-radius:4px;margin:8px;}.ec{margin:0 6px 6px;padding:6px;}.b .ec .ec{border-color:#e9ebee;margin:6px 0 0;}.eu{display:inline-block;}.et{margin-top:5px;}.el,.em{margin:5px 0;}.ec a,.ec a:visited{color:#2b55ad;}.ec a:hover,.ec a:focus{background:#2b55ad;color:#fff;}.eb{font-size:small;}.dz{list-style:none;margin:0;padding:0;}.ee tr{font-size:inherit;}.ei{font-size:small;}.ef{position:relative;}.ew{margin-left:-7px;}.ev{display:inline-block;}.b a:hover .fe .ff,.b a:hover .fe .fh,.b a:hover .fl{color:#fff;}.b .fe{text-align:center;width:40px;}.fe .fh{color:#ec1c2b;font-size:11px;line-height:11px;padding-top:8px;}.fe .ff{color:#1d2129;font-size:30px;font-weight:300;line-height:30px;margin-bottom:-6px;position:relative;}.fs{margin:0 1px;}.ft{background-repeat:no-repeat;background-size:contain;color:transparent;display:inline-block;text-decoration:none;text-shadow:none;vertical-align:text-bottom;}.ft::selection{background-color:highlight;color:transparent;}.ey{white-space:nowrap;}.eq{position:relative;}.eq:after{border:1px solid rgba(0, 0, 0, .1);bottom:0;content:'';left:0;position:absolute;right:0;top:0;}.eo .er{background:#f2f2f2;display:inline-block;margin:0 3px 3px 0;}.eo .er.es{margin-right:0;}.fw{color:#6d84b4;}.b a:hover .fw,.b a:focus .fw{color:#fff;}.b .fw{display:inline-block;}.b .fu{white-space:nowrap;}.fv{direction:ltr;unicode-bidi:isolate;}.fx{unicode-bidi:isolate;}.fr{margin-right:3px;vertical-align:-2px;}.b a.fp{color:gray;display:inline-block;}.fq.s{margin-right:3px;vertical-align:baseline;}.ez{display:inline-block;margin-right:3px;vertical-align:middle;}.fa{border:1px solid #ccc;margin:5px 0;word-wrap:break-word;}.b .fa .fd{padding-right:4px;}.fb{display:block;}.b .fb,.b .fb:visited{color:#3e4350;}.b .fb:focus,.b .fb:hover,.b .fb:focus .fa,.b .fb:hover .fa{background:#3b5998;color:#fff;}.eb .fj{font-size:small;}.fk{color:#4b4f56;}.fn,.fn.fn.fn.fn{position:relative;}body{text-align:left;direction:ltr;}body,tr,input,textarea,button{font-family:sans-serif;}body,p,figure,h1,h2,h3,h4,h5,h6,ul,ol,li,dl,dd,dt{margin:0;padding:0;}h1,h2,h3,h4,h5,h6{font-size:1em;font-weight:bold;}ul,ol{list-style:none;}article,aside,figcaption,figure,footer,header,nav,section{display:block;}.d #viewport{margin:0 auto;max-width:600px;}.i{background-color:#3b5998;}#page{position:relative;}.r,.r.s{display:block;}.o{display:block;}.p{height:20px;width:20px;}.k{background:#3b5998;padding:0 4px 4px;height:22px;}.k.k .x{background:#fff;border:1px solid #243872;-webkit-box-sizing:border-box;font-size:small;height:22px;margin:0;width:100%;}.l.k{padding:1px 1px 3px;}.k .q{padding:1px 3px 0 0;}.k.k.k .bc{background:#627aba;border:1px solid #2e417e;color:#fff;font-size:x-small;font-weight:normal;height:22px;line-height:20px;margin-left:3px;}.j{padding:2px 3px;}.v{border:0;display:block;margin:0;padding:0;}.gh{font-size:small;padding:7px 8px 8px;}.gy{border:1px solid;border-color:#8d949e;border-radius:4px;display:block;margin-top:8px;padding:4px;text-align:center;}.gw{display:block;font-size:x-small;margin:-3px -3px 1px -3px;padding:3px;}.b .gh td.gv{padding-right:4px;}.b .gh td.gx{padding-left:4px;}.gh.gi{background-color:#444950;}.gi{border-top:1px solid #444950;color:#bec3c9;}.b .gi a,.b .gi a:visited{color:#bec3c9;}.b .gi a:focus,.b .gi a:hover{background:#dadde1;color:#1d2129;}.gk{margin-bottom:8px;}.gh.gi .gk>table{background:#d3d7dc;border:1px solid #444950;}.gr{background:#d3d7dc;}.gj .gu{height:24px;line-height:24px;margin-left:2px;}.gm{background:#fff;}.gj .gs{background-color:transparent;color:#4b4f56;display:block;padding:0;width:100%;}.gn .s{display:block;}.gj .gl .gt{padding:2px;}.gj .gl .gn{padding:4px;}.b .gj .gl{border:1px solid #8d949e;}.be{padding-bottom:1px;}.bf{display:inline-block;font-size:small;padding:2px 4px 2px;}.bi{color:#fff496;}.b a:hover .bi,.b a:focus .bi,.bf:hover .bi,.bf:focus .bi{color:#365899;}.bf.bh{background-color:#6d84b4;}/]]>*/</style>

@m-el-azzouzi
Copy link

I had a similar issue, I used fbchat._state.FB_DTSG_REGEX = re.compile(r'"token":"(.*?)"') to solve it but I don't think it will work for you from your output....

JasperMertens pushed a commit to JasperMertens/Spyfall that referenced this issue Mar 21, 2021
@orzechszek
Copy link

if "cookie" in r.url:
beg = r.text.find("action=")+8
end = r.text.find(""", beg)
urlCookies = "https://m.facebook.com" + r.text[beg:end]
payload = {i["name"]:i["value"] for i in find_input_fields(r.text).find_all('input')}
r = session.post(urlCookies, data=payload)

If it works, please also update in v1 project - fbchat 1.9.7 available through pip.

@MS-Jahan
Copy link

I used it, but now i have error:
Attempt #1 failed, retrying
Traceback (most recent call last):
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_client.py", line 205, in login
self._state = State.login(
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 157, in login
return cls.from_session(session=session)
File "C:\Users\krzysiek\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fbchat_state.py", line 196, in from_session
revision = int(r.text.split('"client_revision":', 1)[1].split(",", 1)[0])
IndexError: list index out of range

I've faced this problem and I had to change the _state.py file several times. Here is the latest file I'm using:

# -*- coding: UTF-8 -*-
from __future__ import unicode_literals

import attr
import bs4
import re
import requests
import random

from . import _graphql, _util, _exception

FB_DTSG_REGEX = re.compile(r'name="fb_dtsg" value="(.*?)"')


def get_user_id(session):
    # TODO: Optimize this `.get_dict()` call!
    rtn = session.cookies.get_dict().get("c_user")
    if rtn is None:
        raise _exception.FBchatException("Could not find user id")
    return str(rtn)


def find_input_fields(html):
    return bs4.BeautifulSoup(html, "html.parser", parse_only=bs4.SoupStrainer("input"))


def session_factory(user_agent=None):
    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)
    return session


def client_id_factory():
    return hex(int(random.random() * 2 ** 31))[2:]


def is_home(url):
    parts = _util.urlparse(url)
    # Check the urls `/home.php` and `/`
    return "home" in parts.path or "/" == parts.path


def _2fa_helper(session, code, r):
    soup = find_input_fields(r.text)
    data = dict()

    url = "https://m.facebook.com/login/checkpoint/"

    data["approvals_code"] = code
    data["fb_dtsg"] = soup.find("input", {"name": "fb_dtsg"})["value"]
    data["nh"] = soup.find("input", {"name": "nh"})["value"]
    data["submit[Submit Code]"] = "Submit Code"
    data["codes_submitted"] = 0
    _util.log.info("Submitting 2FA code.")

    r = session.post(url, data=data)

    if is_home(r.url):
        return r

    del data["approvals_code"]
    del data["submit[Submit Code]"]
    del data["codes_submitted"]

    data["name_action_selected"] = "save_device"
    data["submit[Continue]"] = "Continue"
    _util.log.info("Saving browser.")
    # At this stage, we have dtsg, nh, name_action_selected, submit[Continue]
    r = session.post(url, data=data)

    if is_home(r.url):
        return r

    del data["name_action_selected"]
    _util.log.info("Starting Facebook checkup flow.")
    # At this stage, we have dtsg, nh, submit[Continue]
    r = session.post(url, data=data)

    if is_home(r.url):
        return r

    del data["submit[Continue]"]
    data["submit[This was me]"] = "This Was Me"
    _util.log.info("Verifying login attempt.")
    # At this stage, we have dtsg, nh, submit[This was me]
    r = session.post(url, data=data)

    if is_home(r.url):
        return r

    del data["submit[This was me]"]
    data["submit[Continue]"] = "Continue"
    data["name_action_selected"] = "save_device"
    _util.log.info("Saving device again.")
    # At this stage, we have dtsg, nh, submit[Continue], name_action_selected
    r = session.post(url, data=data)
    return r


@attr.s(slots=True)  # TODO i Python 3: Add kw_only=True
class State(object):
    """Stores and manages state required for most Facebook requests."""

    user_id = attr.ib()
    _fb_dtsg = attr.ib()
    _revision = attr.ib()
    _session = attr.ib(factory=session_factory)
    _counter = attr.ib(0)
    _client_id = attr.ib(factory=client_id_factory)
    _logout_h = attr.ib(None)

    def get_params(self):
        self._counter += 1  # TODO: Make this operation atomic / thread-safe
        return {
            "__a": 1,
            "__req": _util.str_base(self._counter, 36),
            "__rev": self._revision,
            "fb_dtsg": self._fb_dtsg,
        }

    @classmethod
    def login(cls, email, password, on_2fa_callback, user_agent=None):
        session = session_factory(user_agent=user_agent)

        soup = find_input_fields(session.get("https://m.facebook.com/").text)
        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)

        # Usually, 'Checkpoint' will refer to 2FA
        if "checkpoint" in r.url and ('id="approvals_code"' in r.text.lower()):
            code = on_2fa_callback()
            r = _2fa_helper(session, code, r)

        # Sometimes Facebook tries to show the user a "Save Device" dialog
        if "save-device" in r.url:
            r = session.get("https://m.facebook.com/login/save-device/cancel/", allow_redirects=True)

        ### SJS Changed here

        # 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:
            raise _exception.FBchatUserError(
                "Login failed. Check email/password. "
                "(Failed on url: {})".format(r.url)
            )

    def is_logged_in(self):
        # Send a request to the login url, to see if we're directed to the home page
        url = "https://m.facebook.com/login.php?login_attempt=1"
        r = self._session.get(url, allow_redirects=False)
        return "Location" in r.headers and is_home(r.headers["Location"])

    def logout(self):
        logout_h = self._logout_h
        if not logout_h:
            url = _util.prefix_url("/bluebar/modern_settings_menu/")
            h_r = self._session.post(url, data={"pmid": "4"})
            logout_h = re.search(r'name=\\"h\\" value=\\"(.*?)\\"', h_r.text).group(1)

        url = _util.prefix_url("/logout.php")
        return self._session.get(url, params={"ref": "mb", "h": logout_h}).ok

    ### sjs Changed here

    @classmethod
    def from_session(cls, session):
        # TODO: Automatically set user_id when the cookie changes in the session
        user_id = get_user_id(session)

        r = session.get(_util.prefix_url("/"))
        print("URL", r.url)
        soup = find_input_fields(r.text)

        with open("log1.html", "w") as f:
            f.write(str(r.text))

        fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"})

        print("\n\nfb_dtsg_element:\n")
        print(fb_dtsg_element)

        if fb_dtsg_element:
            fb_dtsg = fb_dtsg_element["value"]
        else:
            # Fall back to searching with a regex
            fb_dtsg = ''
            try:
                fb_dtsg = FB_DTSG_REGEX.search(r.text).group(1)
            except:
                pass
            
            if 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\nfb_dtsg:\n")
                print(fb_dtsg)
        
        print("\n\nfb_dtsg:\n")
        print(fb_dtsg)

        with open("log1.html", "w") as f:
            f.write(str(r.text))

        revision = int(r.text.split('"client_revision":')[1].split(",", 1)[0])
        print("revision", revision)

        logout_h_element = soup.find("input", {"name": "h"})
        logout_h = logout_h_element["value"] if logout_h_element else None

        return cls(
            user_id=user_id,
            fb_dtsg=fb_dtsg,
            revision=revision,
            session=session,
            logout_h=logout_h,
        )

    def get_cookies(self):
        return self._session.cookies.get_dict()

    @classmethod
    def from_cookies(cls, cookies, user_agent=None):
        session = session_factory(user_agent=user_agent)
        session.cookies = requests.cookies.merge_cookies(session.cookies, cookies)
        return cls.from_session(session=session)

    def _do_refresh(self):
        # TODO: Raise the error instead, and make the user do the refresh manually
        # It may be a bad idea to do this in an exception handler, if you have a better method, please suggest it!
        _util.log.warning("Refreshing state and resending request")
        new = State.from_session(session=self._session)
        self.user_id = new.user_id
        self._fb_dtsg = new._fb_dtsg
        self._revision = new._revision
        self._counter = new._counter
        self._logout_h = new._logout_h or self._logout_h

    def _get(self, url, params, error_retries=3):
        params.update(self.get_params())
        r = self._session.get(_util.prefix_url(url), params=params)
        content = _util.check_request(r)
        j = _util.to_json(content)
        try:
            _util.handle_payload_error(j)
        except _exception.FBchatPleaseRefresh:
            if error_retries > 0:
                self._do_refresh()
                return self._get(url, params, error_retries=error_retries - 1)
            raise
        return j

    def _post(self, url, data, files=None, as_graphql=False, error_retries=3):
        data.update(self.get_params())
        r = self._session.post(_util.prefix_url(url), data=data, files=files)
        content = _util.check_request(r)
        try:
            if as_graphql:
                return _graphql.response_to_json(content)
            else:
                j = _util.to_json(content)
                # TODO: Remove this, and move it to _payload_post instead
                # We can't yet, since errors raised in here need to be caught below
                _util.handle_payload_error(j)
                return j
        except _exception.FBchatPleaseRefresh:
            if error_retries > 0:
                self._do_refresh()
                return self._post(
                    url,
                    data,
                    files=files,
                    as_graphql=as_graphql,
                    error_retries=error_retries - 1,
                )
            raise

    def _payload_post(self, url, data, files=None):
        j = self._post(url, data, files=files)
        try:
            return j["payload"]
        except (KeyError, TypeError):
            raise _exception.FBchatException("Missing payload: {}".format(j))

    def _graphql_requests(self, *queries):
        data = {
            "method": "GET",
            "response_format": "json",
            "queries": _graphql.queries_to_json(*queries),
        }
        return self._post("/api/graphqlbatch/", data, as_graphql=True)

    def _upload(self, files, voice_clip=False):
        """Upload files to Facebook.

        `files` should be a list of files that requests can upload, see
        `requests.request <https://docs.python-requests.org/en/master/api/#requests.request>`_.

        Return a list of tuples with a file's ID and mimetype.
        """
        file_dict = {"upload_{}".format(i): f for i, f in enumerate(files)}

        data = {"voice_clip": voice_clip}

        j = self._payload_post(
            "https://upload.facebook.com/ajax/mercury/upload.php", data, files=file_dict
        )

        if len(j["metadata"]) != len(files):
            raise _exception.FBchatException(
                "Some files could not be uploaded: {}, {}".format(j, files)
            )

        return [
            (data[_util.mimetype_to_key(data["filetype"])], data["filetype"])
            for data in j["metadata"]
        ]

    def _do_send_request(self, data):
        offline_threading_id = _util.generateOfflineThreadingID()
        data["client"] = "mercury"
        data["author"] = "fbid:{}".format(self.user_id)
        data["timestamp"] = _util.now()
        data["source"] = "source:chat:web"
        data["offline_threading_id"] = offline_threading_id
        data["message_id"] = offline_threading_id
        data["threading_id"] = _util.generateMessageID(self._client_id)
        data["ephemeral_ttl_mode:"] = "0"
        j = self._post("/messaging/send/", data)

        # update JS token if received in response
        fb_dtsg = _util.get_jsmods_require(j, 2)
        if fb_dtsg is not None:
            self._fb_dtsg = fb_dtsg

        try:
            message_ids = [
                (action["message_id"], action["thread_fbid"])
                for action in j["payload"]["actions"]
                if "message_id" in action
            ]
            if len(message_ids) != 1:
                log.warning("Got multiple message ids' back: {}".format(message_ids))
            return message_ids[0]
        except (KeyError, IndexError, TypeError) as e:
            raise _exception.FBchatException(
                "Error when sending message: "
                "No message IDs could be found: {}".format(j)
            )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants