From d7f2bb3e8b1e64226b7fc4213fe30013da522a77 Mon Sep 17 00:00:00 2001 From: Tim Chan Date: Tue, 4 Apr 2017 20:05:50 +1000 Subject: [PATCH 1/6] Adding 2FA Support Rudamentary 2FA support --- fbchat/client.py | 68 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 195d7dd..62a018e 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -46,6 +46,7 @@ RemoveUserURL="https://www.facebook.com/chat/remove_participants/" LogoutURL ="https://www.facebook.com/logout.php" AllUsersURL ="https://www.facebook.com/chat/user_info_all" SaveDeviceURL="https://m.facebook.com/login/save-device/cancel/" +CheckpointURL="https://m.facebook.com/login/checkpoint/" facebookEncoding = 'UTF-8' # Log settings @@ -228,17 +229,78 @@ class Client(object): data['login'] = 'Log In' r = self._cleanPost(LoginURL, data) - - # Sometimes Facebook tries to show the user a "Save Device" dialog + log.info(r.text) + + if 'checkpoint' in r.url: + r = self._2FA(r) + if 'save-device' in r.url: r = self._cleanGet(SaveDeviceURL) + log.info(r.url) + if 'home' in r.url: self._post_login() return True else: return False + + def _2FA(self,r): + soup = bs(r.text, "lxml") + data = dict() + s = raw_input('Please enter your 2FA code --> ') + data['approvals_code'] = s + 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 + log.info('Submitting 2FA code') + r = self._cleanPost(CheckpointURL, data) + + log.info(r.url) + if 'home' in 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' + log.info('Saving browser') #At this stage, we have dtsg, nh, name_action_selected, submit[Continue] + r = self._cleanPost(CheckpointURL, data) + + log.info(r.url) + if 'home' in r.url: + return r + + del(data['name_action_selected']) + log.info(data.values()) #At this stage, we have dtsg, nh, submit[Continue] + r = self._cleanPost(CheckpointURL, data) + + log.info(r.url) + if 'home' in r.url: + return r + + del(data['submit[Continue]']) + data['submit[This was me]'] = 'This Was Me' + log.info('Verifying login attempt') #At this stage, we have dtsg, nh, submit[This was me] + r = self._cleanPost(CheckpointURL, data) + + log.info(r.url) + if 'home' in r.url: + return r + + del(data['submit[This was me]']) + data['submit[Continue]'] = 'Continue' + data['name_action_selected'] = 'save_device' + log.info('Saving device again') #At this stage, we have dtsg, nh, submit[Continue], name_action_selected + r = self._cleanPost(CheckpointURL, data) + + log.info(r.url) + return r + def saveSession(self, sessionfile): """Dumps the session cookies to (sessionfile). WILL OVERWRITE ANY EXISTING FILE @@ -280,7 +342,7 @@ class Client(object): for i in range(1,max_retries+1): if not self._login(): log.warning("Attempt #{} failed{}".format(i,{True:', retrying'}.get(i<5,''))) - time.sleep(1) + time.sleep(1000) continue else: log.info("Login successful") From de6880d933c1e743ada173aa48fd8af026c617a0 Mon Sep 17 00:00:00 2001 From: Tim Chan Date: Tue, 4 Apr 2017 20:08:07 +1000 Subject: [PATCH 2/6] Update client.py --- fbchat/client.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 62a018e..33c9e7e 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -229,7 +229,7 @@ class Client(object): data['login'] = 'Log In' r = self._cleanPost(LoginURL, data) - log.info(r.text) + if 'checkpoint' in r.url: r = self._2FA(r) @@ -237,8 +237,6 @@ class Client(object): if 'save-device' in r.url: r = self._cleanGet(SaveDeviceURL) - log.info(r.url) - if 'home' in r.url: self._post_login() return True @@ -257,8 +255,6 @@ class Client(object): log.info('Submitting 2FA code') r = self._cleanPost(CheckpointURL, data) - - log.info(r.url) if 'home' in r.url: return r @@ -271,7 +267,6 @@ class Client(object): log.info('Saving browser') #At this stage, we have dtsg, nh, name_action_selected, submit[Continue] r = self._cleanPost(CheckpointURL, data) - log.info(r.url) if 'home' in r.url: return r @@ -279,7 +274,6 @@ class Client(object): log.info(data.values()) #At this stage, we have dtsg, nh, submit[Continue] r = self._cleanPost(CheckpointURL, data) - log.info(r.url) if 'home' in r.url: return r @@ -288,7 +282,6 @@ class Client(object): log.info('Verifying login attempt') #At this stage, we have dtsg, nh, submit[This was me] r = self._cleanPost(CheckpointURL, data) - log.info(r.url) if 'home' in r.url: return r @@ -297,8 +290,6 @@ class Client(object): data['name_action_selected'] = 'save_device' log.info('Saving device again') #At this stage, we have dtsg, nh, submit[Continue], name_action_selected r = self._cleanPost(CheckpointURL, data) - - log.info(r.url) return r def saveSession(self, sessionfile): From 10430a5c5fa1e30c61ac25eb72ee650c1bddfbe4 Mon Sep 17 00:00:00 2001 From: Tim Chan Date: Tue, 4 Apr 2017 20:09:28 +1000 Subject: [PATCH 3/6] Update client.py --- fbchat/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbchat/client.py b/fbchat/client.py index 33c9e7e..37c5138 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -333,7 +333,7 @@ class Client(object): for i in range(1,max_retries+1): if not self._login(): log.warning("Attempt #{} failed{}".format(i,{True:', retrying'}.get(i<5,''))) - time.sleep(1000) + time.sleep(1) continue else: log.info("Login successful") From 83b5918a6d5886e30354601955543f0a62d7a109 Mon Sep 17 00:00:00 2001 From: Tim Chan Date: Tue, 4 Apr 2017 20:12:00 +1000 Subject: [PATCH 4/6] Update client.py --- fbchat/client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 37c5138..1dbbe4c 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -230,11 +230,12 @@ class Client(object): r = self._cleanPost(LoginURL, data) - + # Usually, 'Checkpoint' will refer to 2FA if 'checkpoint' in r.url: r = self._2FA(r) - if 'save-device' in r.url: + # Sometimes Facebook tries to show the user a "Save Device" dialog + if 'save-device' in r.url and 'Enter Security Code to Continue' in r.text: r = self._cleanGet(SaveDeviceURL) if 'home' in r.url: From fd6a3ab3e4752766fcc977ae1355ec47ac604807 Mon Sep 17 00:00:00 2001 From: Tim Chan Date: Tue, 4 Apr 2017 20:17:13 +1000 Subject: [PATCH 5/6] Added 2FA Support Added new function _2FA. Specified that two things that are definitely shown when 2FA is enabled --- fbchat/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 1dbbe4c..dcc40b5 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -231,11 +231,11 @@ class Client(object): r = self._cleanPost(LoginURL, data) # Usually, 'Checkpoint' will refer to 2FA - if 'checkpoint' in r.url: + if 'checkpoint' in r.url and 'Enter Security Code to Continue' in r.text: r = self._2FA(r) # Sometimes Facebook tries to show the user a "Save Device" dialog - if 'save-device' in r.url and 'Enter Security Code to Continue' in r.text: + if 'save-device' in r.url: r = self._cleanGet(SaveDeviceURL) if 'home' in r.url: From ca606b04b86320eabeb819afef1c754174772006 Mon Sep 17 00:00:00 2001 From: Tim Chan Date: Tue, 4 Apr 2017 20:18:55 +1000 Subject: [PATCH 6/6] Added logging --- fbchat/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbchat/client.py b/fbchat/client.py index dcc40b5..3cad503 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -272,7 +272,7 @@ class Client(object): return r del(data['name_action_selected']) - log.info(data.values()) #At this stage, we have dtsg, nh, submit[Continue] + log.info('Starting Facebook checkup flow') #At this stage, we have dtsg, nh, submit[Continue] r = self._cleanPost(CheckpointURL, data) if 'home' in r.url: