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

Can't login in v2.0.0a3 but can in previous versions #582

Open
wetmore opened this issue May 26, 2020 · 16 comments
Open

Can't login in v2.0.0a3 but can in previous versions #582

wetmore opened this issue May 26, 2020 · 16 comments

Comments

@wetmore
Copy link

wetmore commented May 26, 2020

Description of the problem

Attempting to login using fbchat v2.0.0a3 throws an error, see Traceback below. I can login as expected using 2.0.0a2 and 1.9.6..

Someone else has had the same problem, and could also solve by using v2.0.0a2, see #581

Seems related to the solution to #413, in particular commit 079d409

Code to reproduce

import fbchat

session = fbchat.Session.login("<username snipped>", "<password snipped>")

Traceback

Traceback (most recent call last):
  File "hello.py", line 4, in <module>
    session = fbchat.Session.login("<username snipped>", "<password snipped>")
  File "/Users/matt/programming/python/patrick2/venv/lib/python3.7/site-packages/fbchat/_session.py", line 290, in login
    raise _exception.NotLoggedIn(error)
fbchat.NotLoggedIn: Password Forgot account?

Environment information

  • Python version 3.7.7
  • fbchat version 2.0.0a3 (installed with pip install fbchat==2.0.0a3)
@wetmore
Copy link
Author

wetmore commented May 26, 2020

I did a little poking around. I suppose the more relevant commit here is 7be2aca, which adds the code which throws the error:

# We weren't redirected, hence the email or password was wrong
if not url:
    error = get_error_data(r.content.decode("utf-8"))
    raise _exception.NotLoggedIn(error)

In my case, instead of being redirected to the messenger UI (302), the login request gets a response with code 200, and the content of the response is a big blob of html which renders as:

response content

So you can see the error message which is getting parsed out of it ("Password Forgot account?") is just text from the login bar at the top. The error message returned from FB in the picture indicates the issue is actually due to the request being sent.

When I actually go to messenger.com in a browser and log in with my email and password, it's successful. This indicates to me that the problem will be present in the diff between the request that fbchat sends, and the request that messenger.com sends when I login using that page. One option going forwards for me would be to start experimenting with changing the headers and data sent in the login request. However, it seems strange to me that I would have this problem but someone else would be able to login through fbchat just fine.

Can anyone confirm that they can log in using 2.0.0a3? I'm assuming you can @madsmtm.

@wetmore wetmore changed the title Can't login after switch to messenger.com urls Can't login in v2.0.0a3 but can in previous versions May 26, 2020
@xaadu
Copy link
Contributor

xaadu commented May 29, 2020

I can't login! I've tried today! Exact same problem! @wetmore

@wetmore
Copy link
Author

wetmore commented May 30, 2020

I can't login! I've tried today! Exact same problem! @wetmore

In the meantime I am using 2.0.0a2 and it's working fine, can you use that workaround?

@xaadu
Copy link
Contributor

xaadu commented May 30, 2020 via email

@madsmtm
Copy link
Member

madsmtm commented Jun 7, 2020

Thanks for the report!

I can't reproduce it myself, so maybe one of you would like to help me fix it? If so, please follow these instructions:

  • Go to https://www.messenger.com/login in your browser
  • Open your developer tools on the "Inspect" tab
  • Find the form HTML element in there
  • Inside this element, you should see a bunch of hidden input HTML elements, with different names and values. Note these down.
  • Go to Line 272 in _session.py, and try inputting different values, matching the ones you found in the previous step.
  • After a bit of trial and error, you might be able to find out which of these values are required for you to not hit the error.

It's quite a manual approach, and also probably quite hard to follow, so if something here doesn't work, please ask me to elaborate

@xaadu
Copy link
Contributor

xaadu commented Jun 10, 2020

I've been trying for 2 hours and nothing happened! I've tried with sending every single details, but it can't log in.

I've added dynamic details to the session so that every details gets up to date perfectly

d=session.get('https://messenger.com/login').text

inputs=bs4.BeautifulSoup(d, 'html.parser').find_all('input')

data = {
            "jazoest": inputs[0]["value"],
            "lsd": inputs[1]["value"],
            "initial_request_id": inputs[2]["value"],  # any, just has to be present
            "timezone": "-360",
            "lgndim": inputs[4]["value"],
            "lgnrnd": inputs[5]["value"],
            "lgnjs": inputs[6]["value"],
            "email": email,
            "pass": password,
            "login": "1",
            "persistent": inputs[9]["value"],  # Changes the cookie type to have a long "expires"
            "default_persistent": inputs[10]["value"],
        }

Still, can't login! NB: value of the key "lgndim" gets empty string, don't know why, so I've tried adding custom value to that, still doesn't work! (Maybe it is generated after the page load using JS)

After trying to log in many times, I've found that, a cookie generates and then logs in to messenger named "act" followed by a number value, and that is the main problem. I have no idea where the cookie sent from!
Here's an example:
After going to login page: the cookies are -

'cookie': '_fbp=fb.1.1591773315379.820061979; wd=788x625; datr=g4jgXjB4k6l4gPODUwdd4Rt9'

and this cookie is sent by browser on login attempt in browser -

'cookie': '_fbp=fb.1.1591773315379.820061979; wd=788x625; datr=g4jgXjB4k6l4gPODUwdd4Rt9; act=1591773579064%2F1'

See, last act just appeared! When this cookie is available (copied from browser and sent request with the cookie) and I send request to login, it goes to the 2fa page, but if the act is not available in the cookie, then It redirects to the error page @wetmore provided! I'm noob at coding so I don't know what happens here! I've told you everything I could feel about this! And one more thing, the act numbers first some digits matches with the "datr" cookie and more matches with the max-age or something from received headers strict-transport-security maybe! I'm not sure!

I've explained everything I could get on this login, I'll try to explore more If I get free time! I don't know if anything I wrote could help! Please tell me if i should try another way or something!

@madsmtm
Copy link
Member

madsmtm commented Jun 14, 2020

Thanks for the details @xaadu, they've been really helpful!

Like you said, the act cookie is generated using JavaScript (I've seen it as well 😉). To me, it seems to be a combination of the current timestamp (in milliseconds) and a number indicating which number request this was (we set this to 0 always, might not be correct?).

I've added this to the login code, see d650946, and released v2.0.0a5, so please try that out and see if it works for you now.

@madsmtm
Copy link
Member

madsmtm commented Jun 14, 2020

Note to my future self: I managed to get the same error page as you people by inserting an old datr cookie, using that I should be able to improve the error message parsing.

@xaadu
Copy link
Contributor

xaadu commented Jun 15, 2020

Same problem bro! ☹☹ @madsmtm

It's probably best to use headless selenium for the login and then load the cookies and login in messenger using that cookies! (If it's possible) But still, that wouldn't be perfect! Some hosting problem and other problems may occur!

image

@xaadu
Copy link
Contributor

xaadu commented Jun 28, 2020

I've found a way to log in using pyppeteer! I've logged in and got the session perfectly! It sometimes hangs because of some function call! But it works most of the time! Should I polish the code? Or it can't be used because of weight? I didn't give any fallback for the wrong username/pass/2fa code! I'll polish if I'm sure that pyppeteer is usable! Here's the code (Almost unreadable noob code for the testing purpose that needs to be polished perfectly):

import json

import asyncio
from pyppeteer import launch



class sessionGenerator:
    def __init__(self, email:str, password:str):
        # URLS
        self.loginURL = 'https://messenger.com/login/'
        self.passwordURL = 'https://www.messenger.com/login/password/'
        self.loggedInURL = 'https://www.messenger.com/t/'
        self.checkpointURL1 = 'https://www.messenger.com/login/checkpoint_interstitial/'
        self.checkpointURL2 = 'https://www.facebook.com/checkpoint/'

        # Extra Datas
        self.waitUntilLoad = { 'waitUntil': 'load'}
        
        self.email = email
        self.password = password
    

    def getSession(self):
        # Start Async Loop
        loop = asyncio.get_event_loop()
        return loop.run_until_complete(self.main())
    

    def generateCookies(self, cookiesList):
        cookies = dict()
        for cookie in cookiesList:
            cookies[cookie['name']]=cookie['value']
        return cookies
    

    def getCodeFor2FA(self):
        return input('Enter Code for 2FA Authentiation: ')
    

    async def ss(self):
        # Take a Screenshot and Save as example.png
        await self.page.screenshot({'path': 'example.png'})
    

    async def getText(self, q):
        try:
            #await self.page.waitForNavigation(self.waitUntilLoad)
            await self.page.waitForSelector(q)
        except:
            pass
        element = await self.page.J(q)
        text = await self.page.evaluate('(element) => element.textContent', element)
        return text
    

    async def pressCPButton(self, t:int=1):
        for i in range(t):
            await self.page.waitForSelector('#checkpointSubmitButton', {'timeout': 500})
            await self.page.click('#checkpointSubmitButton')
            await self.ss()



    async def login(self):
        # Clicks Remember Checkbox for Longer Period Session
        await self.page.waitForSelector('#u_0_0')
        await self.page.click('#u_0_0')

        # Type Email and Password and hit Enter
        await self.page.type('#email', self.email)
        await self.page.type('#pass', self.password)
        await self.page.keyboard.press('Enter')

        # Wait for the full page to load
        await self.page.waitForNavigation(self.waitUntilLoad)

        #disable JS
        await self.page.setJavaScriptEnabled(False)
    

    async def rememberBrowser(self):
        await self.page.click('input[value=dont_save]')
        await self.ss()
        await self.page.keyboard.press('Enter')
        await self.ss()
    

    async def reviewRecentLogin(self):
        await self.pressCPButton(2)
        await self.rememberBrowser()


    async def on2FA(self):
        while self.page.url.startswith(self.checkpointURL1):
            print('Found Checkpoint!')
            await self.ss()

            # Click on Continue Button
            await self.page.click('#XMessengerDotComLoginViewPlaceholder > div > div._3-mr > div > a')
            await self.ss()

            pos = await self.getText('strong')

            while pos=='Two-factor authentication required':
                # Enter Code for 2FA
                code = self.getCodeFor2FA()

                # Hit with code for 2FA
                await self.page.type('#approvals_code', code)
                await self.page.keyboard.press('Enter')

                pos = await self.getText('strong')
                print(pos)
            
            await self.ss()

            # Handle Remember Browser Section
            await self.rememberBrowser()
            pos = await self.getText('strong')
            print(pos)

            # Handle Recent Login
            await self.reviewRecentLogin()

            await self.page.waitForNavigation(self.waitUntilLoad)
            await self.ss()

        return
        
        



    async def main(self):
        # Launch Browser Headless
        browser = await launch()

        # Open Tab
        self.page = await browser.newPage()

        # Load Login Page
        await self.page.goto(self.loginURL, self.waitUntilLoad)
        await self.page.screenshot({'path': 'example.png'})

        if self.page.url.startswith(self.loggedInURL):
            print('Logged In Successfully!')
            return
        else:
            await self.login()

        # Check if email / pass is correct
        if self.page.url==self.passwordURL:
            print('Login Failed. Please check username and password!')
            return
        
        # Check for 2FA
        if self.page.url.startswith(self.loggedInURL):
            print('Logged In Successfully!')
        else:
            print('2FA Enabled')
            await self.on2FA()

        #Take Screenshot for Login Confirmation
        await self.page.screenshot({'path': 'example.png'})

        cookiesList = await self.page.cookies()
        return self.generateCookies(cookiesList)




email=''
password=''

session = sessionGenerator(email, password).getSession()

print(session)

with open('session.json', 'w') as f:
    f.write(json.dumps(session))

Note: example.png will track down where the problem occurs!

Note: This will automatically download the required browser on the first run. So I think it would be supported in any hosting! Selenium is easy but need buildpack in Heroku!

@madsmtm kindly just answer if it's possible to use pyppeteer in fbchat! It's a temporary fix!

@TimLChan
Copy link
Contributor

The code above is a bit bloated to be committed I reckon. You're better off just scraping the _js_datr cookie from a new session on messenger.com.

Add it to your session cookies using:
requests.utils.add_dict_to_cookiejar(session.cookies, {'_js_datr': js_datr})
or
session.cookies.set("_js_datr", js_datr, domain=".messenger.com")

@xaadu
Copy link
Contributor

xaadu commented Oct 17, 2020

Thanks, @TimLChan . I've fixed it the same way you've mentioned but I didn't push in this repo because I was sure It was not gonna work and now it doesn't. All credit goes to Facebook for changing the login system 😑😑😑

So I think the best is to use "pyppeteer" based login system. ☹

@TimLChan
Copy link
Contributor

There's some other session variables that need to get fixed for it to work which I've done on my branch. I haven't written any tests or thoroughly tested them so I haven't raised a PR.

@xaadu
Copy link
Contributor

xaadu commented Oct 17, 2020

Wow! Nice work! Do your code still work? Cause mine doesn't.

@shashankredemption
Copy link

@TimLChan does your fork still work with the new messenger/ig merge?

@jgordonpds
Copy link

I'm actively trying to fix this issue in my fork. Anyone have any updates regarding this?

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

No branches or pull requests

6 participants