Open jaymzh opened 6 years ago
It's possible to extract the relevant IDs from bitlbee's nickname.xml
too; the script (either script) spits out a token, account facebook token <......>
, and account facebook on
works again.
This is a tremendous quality of life improvement. Thanks a lot!
Ahhhh. Yes, the scripts are working just fine.
I was being too quick, and dismissing the "Did you just attempt to sign in" pop-up, which of course stops the SMS code send. Oops.
Ignoring that pop-up and waiting for the SMS made the flow work just fine. Can't believe i didn't try that sooner.
Hi.
I have tried several times to get this to work again. It was working before, but suddenly stopped working for some time ago.
Tried to follow Azizb750's instructions, but still no luck. But I need to quit Pidgin before editing the accounts.xml file, if not it seems like the token gets overwritten by the blank/default one.
When I start Pidgin after entering the token, I always get "An unknown error occurred (1)".
Any idea?
I've been banging my head against this one all night. Was about to give up until I got it to work. For reference, Im using Debian Stretch and Bitlbee via Bitlbee's debian repository.
Got to the point where I rewrote the pidgin token generation script script for bitlbee (bitlbee-purple uses a different location for accounts.xml and apparently doesn't properly know how to write to it, it's a known bug).
https://bugs.bitlbee.org/ticket/1327
I prefer the Glowing Bear frontend for weechat relay over Pidgin /w GTK2/3 or Finch /w tmux/screen. I had to do some system kludges because bitlbee encrypts passwords in its configuration and it doesn't let anyone beyond root and the bitlbee service user account touch the config. I'm able to handle the former by just prompting for the password using getpass.getpass instead of reading it from xml, but the latter has to be done from bitlbee and a shell. I also modified the xml to json conversion to account for the differences in the bitlbee configuration versus libpurple.
Here's my procedure before running the script:
In bitlbee
acc facebook del
save
acc add facebook email password
acc facebook on
acc facebook off
accept the 2FA challenge on website to prevent a lockout
save
The final save command will populate /var/lib/bitlbee/USERNAME.xml with the uid/gid/mid/cid. The UID will always be zero, but that's OK since it will update on the first JSON resquest/response and stay the same after that, along with the DID. The MID should change however during the process.
Command Line as non-privileged user
$ sudo chmod o+x /var/lib/bitlbee
$ sudo chmod o+r /var/lib/bitlbee/USERNAME.xml
Run the script
$ cat /etc/issue
Debian GNU/Linux 9 \n \l
$ dpkg -l | grep bitlbee-common
ii bitlbee-common 3.6-1+20211113+master+36-gcfe7243b-git amd64 IRC to other chat networks gateway (common files/docs)
$ dpkg -l | grep bitlbee-facebook
ii bitlbee-facebook 20210212~8bd37d9~44 amd64 Facebook protocol plugin for BitlBee
$ python3 --version
Python 3.5.3
$ python3 bitlbee-fb-login-2fa.py
Initial Output
Config xml file is: /var/lib/bitlbee/USERNAME.xml
Password:
DEBUG: %s Account UID: 0
DEBUG: %s Account DID: --sanitized--
DEBUG: %s Account MID: --sanitized--
Access Token generator for Facebook 2factor login
This tool will perform 2-factor login to FB and then print out an
access token needed for the FB plugin for bitlbee and pidgin. Take
the resulting code and set the token for facebook in bitlbee
DEBUG: %s status, reason: 200, OK
DEBUG: %s undecoded response: b'{"error_code":406,"error_msg":"Login approvals are on. Expect an SMS shortly with a code to use for log in (406)","error_data":"{\\"machine_id\\":\\"--sanitized--\\",\\"uid\\":--sanitized--,\\"login_first_factor\\":\\"FDl9pFNMcxFgpRek8qAKTsuSaRUpOLUZ\\",\\"support_uri\\":\\"https:\\\\\\/\\\\\\/m.facebook.com\\\\\\/two_factor\\\\\\/id_upload\\\\\\/mobile\\\\\\/?idd=AYjJQ0DH9SwUAxVb3I8bazawWtryrf1DsmTFnqjbvdmyUOhSM1XvMinRtmUenegi7NnakqzjSIA5LmQdjypePeNZ&nonce=iAXIqa3Tiebum5up&ext=1648541875&hash=AeT1dCEPQM3er3ZLa2E\\",\\"auth_token\\":\\"1648282675.tr.s:pw.tDBGAiEAxOGw0e2MlQLJzOdlM8G3Bm25GOkApuy2RcSDAcNthsECIQDch2GzWMlL4CJg4JqWoeg2iEyaSsuBYFNScjNgTpmMAw\\",\\"error_title\\":\\"Login Code Required\\",\\"error_message\\":\\"Generate a code from your authentication app or use the code we sent by text message to log in.\\"}","request_args":[{"key":"method","value":"auth.login"},{"key":"uid","value":"0"},{"key":"email","value":"--sanitized--"},{"key":"password","value":"--sanitized--"},{"key":"fb_api_req_friendly_name","value":"authenticate"},{"key":"format","value":"json"},{"key":"sig","value":"977a1ac7d0d1cb3e120f58ae7290f4b7"},{"key":"generate_session_cookies","value":"1"},{"key":"api_key","value":"256002347743983"},{"key":"device_id","value":"--sanitized--"},{"key":"locale","value":"en"},{"key":"generate_machine_id","value":"1"}]}'
Traceback (most recent call last):
File "bitlbee-fb-login-2fa.py", line 148, in <module>
response = json.loads(response_data)
File "/usr/lib/python3.5/json/__init__.py", line 312, in loads
s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'
The script dies before it can load the first request's response data. Some quick googling tells me I need to use decode('utf-8'), so I modified the two instances in the script
from:
response = json.loads(response_data)
to
response = json.loads(response_data.decode('utf-8'))
After those changes, on the next attempt, we finally have something! We get prompted for the 2FA code (note: I wore out my welcome on SMS 2FA debugging, but as other people pointed out codes from your authenticator app work fine). After entering it we get another error, but we also get the Access Token!
DEBUG: %s {'error_data': '{"machine_id":"--sanitized--","uid":--sanitized--,"login_first_factor":"FDl9pFNMcxFgpRek8qAKTsuSaRUpOLUZ","support_uri":"https:\\/\\/m.facebook.com\\/two_factor\\/id_upload\\/mobile\\/?idd=AYjJQ0DH9SwUAxVb3I8bazawWtryrf1DsmTFnqjbvdmyUOhSM1XvMinRtmUenegi7NnakqzjSIA5LmQdjypePeNZ&nonce=iAXIqa3Tiebum5up&ext=1648541875&hash=AeT1dCEPQM3er3ZLa2E","auth_token":"1648282675.tr.s:pw.tDBGAiEAxOGw0e2MlQLJzOdlM8G3Bm25GOkApuy2RcSDAcNthsECIQDch2GzWMlL4CJg4JqWoeg2iEyaSsuBYFNScjNgTpmMAw","error_title":"Login Code Required","error_message":"Generate a code from your authentication app or use the code we sent by text message to log in."}', 'request_args': [{'key': 'method', 'value': 'auth.login'}, {'key': 'uid', 'value': '0'}, {'key': 'email', 'value': '--sanitized--'}, {'key': 'password', 'value': '--sanitized--'}, {'key': 'fb_api_req_friendly_name', 'value': 'authenticate'}, {'key': 'format', 'value': 'json'}, {'key': 'sig', 'value': '977a1ac7d0d1cb3e120f58ae7290f4b7'}, {'key': 'generate_session_cookies', 'value': '1'}, {'key': 'api_key', 'value': '256002347743983'}, {'key': 'device_id', 'value': '--sanitized--'}, {'key': 'locale', 'value': 'en'}, {'key': 'generate_machine_id', 'value': '1'}], 'error_msg': 'Login approvals are on. Expect an SMS shortly with a code to use for log in (406)', 'error_code': 406}
Code: --sanitized--
DEBUG: %s FB Account UID: --sanitized--
FB Account DID not present in error_data: equal to CONFIGFILE.xml did
DEBUG: %s FB Account MID: --sanitized-- (Different value)
DEBUG: %s status, reason: 200, OK
DEBUG: %s undecoded response: b'{"session_key":"5.2B_90p2gYtEZbQ.1648282680.44---sanitized--","uid":--sanitized--,"secret":"5322e5eea92b31d35fe5759b607175b7","access_token":"--sanitized--","machine_id":"OMw-YlVqiess-DymY0U9Bp_f","session_cookies":[{"name":"c_user","value":"--sanitized--","expires":"Sun, 26 Mar 2023 08:18:00 GMT","expires_timestamp":1679818680,"domain":".facebook.com","path":"\\/","secure":true},{"name":"xs","value":"44:2B_90p2gYtEZbQ:2:1648282680:-1:2878","expires":"Sun, 26 Mar 2023 08:18:00 GMT","expires_timestamp":1679818680,"domain":".facebook.com","path":"\\/","secure":true,"httponly":true},{"name":"fr","value":"0by5rp800nXJJa6VE.AWUm-omy2nw5qxZcc5R5aIqioiw.BiPsw4..AAA.0.0.BiPsw4.AWVoWUowGYE","expires":"Fri, 24 Jun 2022 08:17:58 GMT","expires_timestamp":1656058678,"domain":".facebook.com","path":"\\/","secure":true,"httponly":true},{"name":"datr","value":"OMw-YlVqiess-DymY0U9Bp_f","expires":"Mon, 25 Mar 2024 08:18:00 GMT","expires_timestamp":1711354680,"domain":".facebook.com","path":"\\/","secure":true,"httponly":true}],"user_storage_key":"632766dc3ef8444f125aabab0720310762e228d8523c8a8ad67395d8269c025f"}'
Access token: --sanitized--
Traceback (most recent call last):
File "bitlbee-fb-login-2fa.py", line 193, in <module>
if ( DID != response['device_id'] ):
KeyError: 'device_id'
I ran the following in bitlbee afterward
acc facebook set token ACCESS_TOKEN
acc facebook on
And it connects! Simply set your options and setup your control channel.
acc facebook set OPTION VALUE
/join &facebook
chan list
chan $N set auto_join true
acc facebook off
acc facebook on
save
To open the control channel on connect, you have to join the control channel, find it in the channel list, and set auto_join on the channel id to true. The final save command will automatically revert your changes to permissions on /var/lib/bitlbee and /var/lib/bitlbee/USERNAME.xml
Looking at the behavior of the script and the JSON requests, I think what is happening is that on the first JSON request, the Facebook API is generating a new DID on its end using uuidgen or something similar and expects the same UUID for the next JSON request/response. I noticed when I finally connected and saved my bitlbee config that the DID stayed the same after the initial response and after bitlbee connected and the config was saved. You still get the KeyError, but you should still get the Access Token since it's in a try/execpt block and the UUID-format DID does not appear to change.
I have uploaded my modified script for bitlbee users to a gist for reference:
https://gist.github.com/Tatsujin/953551fe38d8e38aac43b423998d3deb
I hope you find this useful. If you are using the pidgin script, you might want to try making the decode changes I suggested for the json_loads. Good luck!
Thanks, @Tatsujin - i've upated my script to include the utf-8 parsing as well.
https://raw.githubusercontent.com/akhepcat/Miscellaneous/master/pidgin-fb-login-2fa.py
Thanks akhepcat for creating this script.
I tried it, but got the following error:
Traceback (most recent call last):
File "./pidgin-fb-login-2fa.py", line 181, in
Thanks akhepcat for creating this script.
I tried it, but got the following error:
Traceback (most recent call last): File "./pidgin-fb-login-2fa.py", line 181, in error_data = json.loads(response['error_data'].decode('utf-8')) AttributeError: 'str' object has no attribute 'decode'
Ah, try removing the ".decode('utf-8')" from that line.
It worked here on my test, but maybe it's failing in some cases, and may not really be needed.
Hi and thanks for the quick reply.
Tried to remove the decode part, and then I get the token. But also the following error after entering the code:
FB Account DID not present in error_data: equal to accounts.xml did
Access token: ***
Traceback (most recent call last):
File "./pidgin-fb-login-2fa.py", line 212, in
Tried to add the token to accounts.xml manually, but still get the "An unknown error occurred (1)" when I tries to connect. This is probably not something wrong with the script, but something else. Tried to delete and set up the Facebook account again in Pidgin, but same issue. I get a security notice in Facebook when I try to connect, but I click "Yes, it was me" and "Save browser". But still no luck when try to connect.
Hi and thanks for the quick reply.
Tried to remove the decode part, and then I get the token. But also the following error after entering the code:
FB Account DID not present in error_data: equal to accounts.xml did Access token: *** Traceback (most recent call last): File "./pidgin-fb-login-2fa.py", line 212, in if ( DID != response['device_id'] ): KeyError: 'device_id'
Tried to add the token to accounts.xml manually, but still get the "An unknown error occurred (1)" when I tries to connect. This is probably not something wrong with the script, but something else. Tried to delete and set up the Facebook account again in Pidgin, but same issue. I get a security notice in Facebook when I try to connect, but I click "Yes, it was me" and "Save browser". But still no luck when try to connect.
Try the latest version, that should all be fixed now.
Hi and thanks for the quick reply. Tried to remove the decode part, and then I get the token. But also the following error after entering the code: FB Account DID not present in error_data: equal to accounts.xml did Access token: *** Traceback (most recent call last): File "./pidgin-fb-login-2fa.py", line 212, in if ( DID != response['device_id'] ): KeyError: 'device_id' Tried to add the token to accounts.xml manually, but still get the "An unknown error occurred (1)" when I tries to connect. This is probably not something wrong with the script, but something else. Tried to delete and set up the Facebook account again in Pidgin, but same issue. I get a security notice in Facebook when I try to connect, but I click "Yes, it was me" and "Save browser". But still no luck when try to connect.
Try the latest version, that should all be fixed now.
Hi I tried the script by @akhepcat on https://raw.githubusercontent.com/akhepcat/Miscellaneous/master/pidgin-fb-login-2fa.py, pasted the xml code in accounts.xml and I get this error: When I try to connect again, the error stays the same :( .
That happens, I think, when it's trying to sync your history and it's too big.
Go to edit account, advanced, uncheck "show unread messages". The connect, it should work. Once that's done, you can re-check that box and it should work.
That happens, I think, when it's trying to sync your history and it's too big.
Go to edit account, advanced, uncheck "show unread messages". The connect, it should work. Once that's done, you can re-check that box and it should work.
Hi. Thanks for the reply Followed your instructions. I unchecked all the boxes in the "Advanced" tab and reconnect. The error stays the same :( .
I ported @jaymzh 's script to python3 and uploaded as a gist here: https://gist.github.com/kflu/1e7c358989b0556e99a919face1ca2f7
Changes:
USAGE:
FBEMAIL=<YOUR_EMAIL> python3 fb_get_token.py
If you have 2FA, it will ask for the 2FA code after you type in password.
OK, just shoving in a UUID seems to work. Combining @jackblk 's stuff with my previous script, this seems to work. Jam your email and a random UUID at the top
#!/usr/bin/python2.7 import sys import cgi from urllib import urlencode import hashlib import getpass import httplib import urllib import json from optparse import OptionParser DEBUG = False # put a UUID in here MACHINE_ID = '' # put your email in here EMAIL = '' FB_API_KEY = '256002347743983' FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895' def fb_sig(data): newdata = data.copy() params = ''.join(['%s=%s' % x for x in sorted(data.items())]) newdata['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest() return newdata def debug(msg): global DEBUG if DEBUG: print "DEBUG: %s", msg if EMAIL == '': print "ERROR: set an email address, please" sys.exit() if MACHINE_ID == '': print "ERROR: set a machine id (to any UUID), please" sys.exit() parser = OptionParser() parser.add_option('-d', '--debug', action='store_true', dest='debug', default=False) (options, args) = parser.parse_args() if options.debug: DEBUG = True data = { "fb_api_req_friendly_name": "authenticate", "locale": "en", "format": "json", "api_key": FB_API_KEY, "method": "auth.login", "generate_session_cookies": "1", "generate_machine_id": "1", "email": EMAIL, "device_id": MACHINE_ID, } data['password'] = getpass.getpass() headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "*/*"} conn = httplib.HTTPSConnection('b-api.facebook.com:443') params = urllib.urlencode(fb_sig(data)) conn.request('POST', '/method/auth.login', params, headers) response = conn.getresponse() debug("status, reason: %s, %s" % (response.status, response.reason)) response_data = response.read() debug("undecoded response: %s" % response_data) response = json.loads(response_data) debug(response) error_data = json.loads(response['error_data']) first_fac = error_data['login_first_factor'] data['credentials_type'] = 'two_factor' data['error_detail_type'] = 'button_with_disabled' data['first_factor'] = first_fac data['twofactor_code'] = getpass.getpass('Code: ') data['password'] = data['twofactor_code'] data['userid'] = error_data['uid'] data['machine_id'] = error_data['machine_id'] params = urllib.urlencode(fb_sig(data)) conn.request('POST', '/method/auth.login', params, headers) response = conn.getresponse() debug("status, reason: %s, %s" % (response.status, response.reason)) response_data = response.read() debug("undecoded response: %s" % response_data) response = json.loads(response_data) print response
But doing as @dequis recommended and putting the resulting
access_token
intotoken
into accounts.xml does not work for me, I still get a "Login approvals are on..." error. Also 'stoken' keeps showing up. I put the token into both token and stoken, but I haven't made it work yet. Anyone else?
BTW, I stopped using my script and used @akhepcat 's fork of my script, it's nicer in that it pulls the password automatically from the file and such.
Up to date script to get token:
https://github.com/kofany/get-fb-token/blob/main/fb-token.py
I reported this in the Workplace bug, but it looks like this is now happening on non-workplace. Two-factor no longer works either in app-password mode, nor in login-approval-code mode.
If you use an app password, you just get permission denied (tried with both "username" and "email" as username).
If you use normal password, Pidgin will tell you about the approval code, you then put it in, and it tries to connect for a minute or so, and then eventually you get
invalid username or password (401)
.