Skip to content

Commit 51206c3

Browse files
committed
Problem: Added Two Factor Authentication feature, intended for protected
accts. If the acct is not protected this feature will be ignored, will go unnoticed. Fixed timgrossmann#5932, Commenting with '@{}' inserts my own username instead of the target's username comment_util.py: replaced unused variables in process_comments() instapy.py: added `security_codes` arg in constructor and login_user() process_comments() now uses `user_name` for commenting a target user. comment_by_locations() now has the same code for process_comments() login_util.py: Added random import due to login_user() feature with Two Factor Authentication. security_codes, must be a list with codes and InstaPy will chose only one element randomly. Added new def two_factor_authentication() xpath_compile.py: Updated get_comments_on_post xpath with a generic form Added pull_request_template.md: to have a format in the PR. instance-settings.md updated with steps for Two Factor Authentication Updated CHANGELOG with commit changes Note:
1 parent cd307b3 commit 51206c3

7 files changed

Lines changed: 205 additions & 71 deletions

File tree

.github/pull_request_template.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!-- Did you know that we have a Discord channel ? Join us: https://discord.gg/FDETsht -->
2+
<!-- Is this a Feature Request ? Please, check out our Wiki first https://github.com/timgrossmann/InstaPy/wiki -->
3+
# Pull Request Template
4+
5+
## Description
6+
7+
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
8+
9+
Do not include any personal data.
10+
11+
Fixes # (issue)
12+
13+
## How Has This Been Tested?
14+
15+
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.
16+
17+
- [ ] Test
18+
19+
## Checklist:
20+
21+
- [ ] I have commented my code, particularly in hard-to-understand areas
22+
- [ ] I have made corresponding changes to the documentation
23+
- [ ] I have checked my code and corrected any misspellings
24+
- [ ] I have performed a self-review of my own code
25+
- [ ] My code follows the style guidelines of this project, `black -t py34`
26+
- [ ] My changes generate no new warnings

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ _The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1313
- Convert Documentation to Docusaurus
1414
- Check if user's account is private
1515
- Added informational message when videos found instead of images in `likers_from_photo`
16+
- Two Factor Authentication check when acct is protected
17+
- Added Pull Request Template
1618

1719
### Fixed
1820

@@ -23,6 +25,7 @@ _The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
2325
- Fixed `get_followers` return for empty list
2426
- Fixed xpath for `likers_from_photo`
2527
- Changed windows size to `iPhone XS Max: 414, 896`
28+
- Fixed `process_comments` where some comments used the InstaPy user
2629

2730
## [0.6.12] - 2020-10-26
2831

docs/instance-settings.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ If the web driver you're using doesn't support headless mode (or the headless mo
1919
session = InstaPy(username='test', password='test', nogui=True)
2020
```
2121

22-
2322
### Bypass Suspicious Login Attempt
2423

2524
InstaPy detects automatically if the Security Code Challenge
@@ -36,20 +35,32 @@ InstaPy(username=insta_username,
3635
bypass_security_challenge_using='sms')
3736
```
3837

38+
### Two Factor Authentication
39+
InstaPy detects automatically if the account is protected with the Two Factor Authentication, if yes InstaPy user need to provide the Security codes in the session constructor; at least one code is required.
40+
41+
Security codes can be found in: `Settings` -> `Security` -> `Two-Factor-Authentication` -> `Backup Codes`
42+
43+
```python
44+
InstaPy(username=insta_username,
45+
password=insta_password,
46+
security_codes=["01234567", "76543210", "01237654"],)
47+
```
48+
3949
### Use a proxy
4050

4151
You can use InstaPy behind a proxy by specifying server address, port and/or proxy authentication credentials. It works with and without ```headless_browser``` option.
4252

4353
Simple proxy setup example:
54+
4455
```python
4556
session = InstaPy(username=insta_username,
4657
password=insta_password,
47-
proxy_address='8.8.8.8',
48-
proxy_port=8080)
49-
58+
proxy_address='8.8.8.8',
59+
proxy_port=8080)
5060
```
5161

5262
Proxy setup with authentication example:
63+
5364
```python
5465
session = InstaPy(username=insta_username,
5566
password=insta_password,
@@ -64,7 +75,8 @@ InstaPy can perform a few checks online, including you connection and the availa
6475

6576
`want_check_browser` default is False, you can set it to True at session start. Recommend to do this if you want to add additional checks for the connection to the web and Instagram.
6677

67-
example:
78+
For example:
79+
6880
```python
6981
session = InstaPy(username=insta_username,
7082
password=insta_password,
@@ -76,15 +88,16 @@ If you're running InstaPy in threads and get exception `ValueError: signal only
7688
There is two ways to do it:
7789

7890
Closing session in smart_run context:
91+
7992
```python
8093
session = InstaPy()
8194
with smart_run(session, threaded=True):
8295
""" Activity flow """
8396
# some activity here ...
8497
```
8598

86-
8799
Closing session with `end()` method
100+
88101
```python
89102
session = InstaPy()
90103
session.login()
@@ -99,7 +112,8 @@ Specifying the Firefox executable path can also help you if you are getting the
99112

100113
`selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities`
101114

102-
example on a Windows machine (with the right path also works on Linux and MAC)
115+
Example on a Windows machine (with the right path also works on Linux and macOS)
116+
103117
```python
104118
session = InstaPy(username=insta_username,
105119
password=insta_password,

instapy/comment_util.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def comment_image(browser, username, comments, blacklist, logger, logfolder):
117117
)
118118
else:
119119
logger.warning(
120-
"--> Comment Action Likely Failed!" "\t~comment Element was not found"
120+
"--> Comment Action Likely Failed!\t~comment Element was not found"
121121
)
122122
return False, "commenting disabled"
123123

@@ -453,12 +453,13 @@ def process_comments(
453453

454454
# smart commenting
455455
if comments and publish:
456-
comment_state, msg = comment_image(
456+
comment_state, _ = comment_image(
457457
browser,
458458
user_name,
459459
selected_comments,
460460
blacklist,
461461
logger,
462462
logfolder,
463463
)
464+
464465
return comment_state

instapy/instapy.py

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def __init__(
124124
geckodriver_path: str = None,
125125
split_db: bool = False,
126126
bypass_security_challenge_using: str = "email",
127+
security_codes: int = 0000,
127128
want_check_browser: bool = True,
128129
browser_executable_path: str = None,
129130
geckodriver_log_level: str = "info", # "info" by default
@@ -158,6 +159,7 @@ def __init__(
158159
self.page_delay = page_delay
159160
self.disable_image_load = disable_image_load
160161
self.bypass_security_challenge_using = bypass_security_challenge_using
162+
self.security_codes = security_codes
161163

162164
# choose environment over static typed credentials
163165
self.username = os.environ.get("INSTA_USER") or username
@@ -430,6 +432,7 @@ def login(self):
430432
self.logfolder,
431433
self.proxy_address,
432434
self.bypass_security_challenge_using,
435+
self.security_codes,
433436
self.want_check_browser,
434437
):
435438
message = (
@@ -1580,7 +1583,7 @@ def like_by_locations(
15801583
self.max_comments,
15811584
self.min_comments,
15821585
self.comments_mandatory_words,
1583-
self.username,
1586+
user_name, # Comments with target user
15841587
self.blacklist,
15851588
self.browser,
15861589
self.logger,
@@ -1763,65 +1766,63 @@ def comment_by_locations(
17631766
except Exception as err:
17641767
self.logger.error("Image check error: {}".format(err))
17651768

1769+
# comments
17661770
if (
17671771
self.do_comment
17681772
and user_name not in self.dont_include
17691773
and checked_img
1774+
and commenting
17701775
):
17711776
comments = self.comments + (
17721777
self.video_comments if is_video else self.photo_comments
17731778
)
17741779

1775-
if comments:
1776-
success = process_comments(
1777-
comments,
1778-
temp_comments,
1779-
self.delimit_commenting,
1780-
self.max_comments,
1781-
self.min_comments,
1782-
self.comments_mandatory_words,
1783-
self.username,
1784-
self.blacklist,
1785-
self.browser,
1786-
self.logger,
1787-
self.logfolder,
1788-
)
1789-
1790-
if success:
1791-
commented += 1
1792-
# reset jump counter after a
1793-
# successful comment
1794-
self.jumps["consequent"]["comments"] = 0
1795-
1796-
# try to follow
1797-
if (
1798-
self.do_follow
1799-
and user_name not in self.dont_include
1800-
and checked_img
1801-
and following
1802-
and not follow_restriction(
1803-
"read",
1804-
user_name,
1805-
self.follow_times,
1806-
self.logger,
1807-
)
1808-
):
1809-
follow_state, msg = follow_user(
1810-
self.browser,
1811-
"post",
1812-
self.username,
1813-
user_name,
1814-
None,
1815-
self.blacklist,
1816-
self.logger,
1817-
self.logfolder,
1818-
)
1819-
if follow_state is True:
1820-
followed += 1
1821-
1822-
else:
1823-
self.logger.info("--> Not following")
1824-
sleep(1)
1780+
success = process_comments(
1781+
comments,
1782+
temp_comments,
1783+
self.delimit_commenting,
1784+
self.max_comments,
1785+
self.min_comments,
1786+
self.comments_mandatory_words,
1787+
user_name, # Comments with target user
1788+
self.blacklist,
1789+
self.browser,
1790+
self.logger,
1791+
self.logfolder,
1792+
)
1793+
if success:
1794+
commented += 1
1795+
# reset jump counter after a
1796+
# successful comment
1797+
self.jumps["consequent"]["comments"] = 0
1798+
# try to follow
1799+
if (
1800+
self.do_follow
1801+
and user_name not in self.dont_include
1802+
and checked_img
1803+
and following
1804+
and not follow_restriction(
1805+
"read",
1806+
user_name,
1807+
self.follow_times,
1808+
self.logger,
1809+
)
1810+
):
1811+
follow_state, msg = follow_user(
1812+
self.browser,
1813+
"post",
1814+
self.username,
1815+
user_name,
1816+
None,
1817+
self.blacklist,
1818+
self.logger,
1819+
self.logfolder,
1820+
)
1821+
if follow_state is True:
1822+
followed += 1
1823+
else:
1824+
self.logger.info("--> Not following")
1825+
sleep(1)
18251826

18261827
elif msg == "jumped":
18271828
# will break the loop after certain
@@ -2015,7 +2016,7 @@ def like_by_tags(
20152016
self.max_comments,
20162017
self.min_comments,
20172018
self.comments_mandatory_words,
2018-
self.username,
2019+
user_name, # Comments with target user
20192020
self.blacklist,
20202021
self.browser,
20212022
self.logger,
@@ -2286,6 +2287,7 @@ def like_by_users(
22862287
"Image check error: {}".format(err)
22872288
)
22882289

2290+
# comments
22892291
if (
22902292
self.do_comment
22912293
and user_name not in self.dont_include
@@ -2304,7 +2306,7 @@ def like_by_users(
23042306
self.max_comments,
23052307
self.min_comments,
23062308
self.comments_mandatory_words,
2307-
self.username,
2309+
user_name, # Comments with target user
23082310
self.blacklist,
23092311
self.browser,
23102312
self.logger,
@@ -2589,7 +2591,7 @@ def interact_by_users(
25892591
self.max_comments,
25902592
self.min_comments,
25912593
self.comments_mandatory_words,
2592-
self.username,
2594+
user_name, # Comments with target user
25932595
self.blacklist,
25942596
self.browser,
25952597
self.logger,
@@ -2882,6 +2884,7 @@ def interact_by_users_tagged_posts(
28822884
temp_comments,
28832885
clarifai_tags,
28842886
) = self.query_clarifai()
2887+
28852888
except Exception as err:
28862889
self.logger.error(
28872890
"Image check error: {}".format(err)
@@ -2900,7 +2903,7 @@ def interact_by_users_tagged_posts(
29002903
self.max_comments,
29012904
self.min_comments,
29022905
self.comments_mandatory_words,
2903-
self.username,
2906+
user_name, # Comments with target user
29042907
self.blacklist,
29052908
self.browser,
29062909
self.logger,
@@ -4051,7 +4054,7 @@ def like_by_feed_generator(
40514054
"Image check error: {}".format(err)
40524055
)
40534056

4054-
# commenting
4057+
# comments
40554058
if (
40564059
self.do_comment
40574060
and user_name not in self.dont_include
@@ -4070,7 +4073,7 @@ def like_by_feed_generator(
40704073
self.max_comments,
40714074
self.min_comments,
40724075
self.comments_mandatory_words,
4073-
self.username,
4076+
user_name, # Comments with target user
40744077
self.blacklist,
40754078
self.browser,
40764079
self.logger,
@@ -4834,6 +4837,7 @@ def interact_by_URL(
48344837
except Exception as err:
48354838
self.logger.error("Image check error: {}".format(err))
48364839

4840+
# comments
48374841
if (
48384842
self.do_comment
48394843
and user_name not in self.dont_include
@@ -4850,7 +4854,7 @@ def interact_by_URL(
48504854
self.max_comments,
48514855
self.min_comments,
48524856
self.comments_mandatory_words,
4853-
self.username,
4857+
user_name, # Comments with target user
48544858
self.blacklist,
48554859
self.browser,
48564860
self.logger,

0 commit comments

Comments
 (0)