1
0
mirror of https://github.com/instaloader/instaloader.git synced 2024-10-27 05:32:30 +01:00

Fix obtaining csrftoken for login

Fixes #122. Further fixes processing of login JSON response regarding error
handling.
This commit is contained in:
Alexander Graf 2018-05-23 08:23:14 +02:00
parent a3eb93c21a
commit 86035b8d2d
2 changed files with 37 additions and 16 deletions

View File

@ -320,7 +320,11 @@ class Instaloader:
return self.context.test_login() return self.context.test_login()
def login(self, user: str, passwd: str) -> None: def login(self, user: str, passwd: str) -> None:
"""Log in to instagram with given username and password and internally store session object""" """Log in to instagram with given username and password and internally store session object.
:raises InvalidArgumentException: If the provided username does not exist.
:raises BadCredentialsException: If the provided password is wrong.
:raises ConnectionException: If connection to Instagram failed."""
self.context.login(user, passwd) self.context.login(user, passwd)
def download_post(self, post: Post, target: str) -> bool: def download_post(self, post: Post, target: str) -> bool:
@ -732,7 +736,9 @@ class Instaloader:
def interactive_login(self, username: str) -> None: def interactive_login(self, username: str) -> None:
"""Logs in and internally stores session, asking user for password interactively. """Logs in and internally stores session, asking user for password interactively.
:raises LoginRequiredException: when in quiet mode.""" :raises LoginRequiredException: when in quiet mode.
:raises InvalidArgumentException: If the provided username does not exist.
:raises ConnectionException: If connection to Instagram failed."""
if self.context.quiet: if self.context.quiet:
raise LoginRequiredException("Quiet mode requires given password or valid session file.") raise LoginRequiredException("Quiet mode requires given password or valid session file.")
password = None password = None

View File

@ -170,29 +170,44 @@ class InstaloaderContext:
return data["data"]["user"]["username"] if data["data"]["user"] is not None else None return data["data"]["user"]["username"] if data["data"]["user"] is not None else None
def login(self, user, passwd): def login(self, user, passwd):
"""Not meant to be used directly, use :meth:`Instaloader.login`.""" """Not meant to be used directly, use :meth:`Instaloader.login`.
:raises InvalidArgumentException: If the provided username does not exist.
:raises BadCredentialsException: If the provided password is wrong.
:raises ConnectionException: If connection to Instagram failed."""
session = requests.Session() session = requests.Session()
session.cookies.update({'sessionid': '', 'mid': '', 'ig_pr': '1', session.cookies.update({'sessionid': '', 'mid': '', 'ig_pr': '1',
'ig_vw': '1920', 'csrftoken': '', 'ig_vw': '1920', 'csrftoken': '',
's_network': '', 'ds_user_id': ''}) 's_network': '', 'ds_user_id': ''})
session.headers.update(self._default_http_header()) session.headers.update(self._default_http_header())
self._sleep() session.headers.update({'X-CSRFToken': self.get_json('', {})['config']['csrf_token']})
resp = session.get('https://www.instagram.com/') # Not using self.get_json() here, because we need to access csrftoken cookie
session.headers.update({'X-CSRFToken': resp.cookies['csrftoken']})
self._sleep() self._sleep()
login = session.post('https://www.instagram.com/accounts/login/ajax/', login = session.post('https://www.instagram.com/accounts/login/ajax/',
data={'password': passwd, 'username': user}, allow_redirects=True) data={'password': passwd, 'username': user}, allow_redirects=True)
session.headers.update({'X-CSRFToken': login.cookies['csrftoken']}) if login.status_code != 200:
if login.status_code == 200: raise ConnectionException("Login error: {} {}".format(login.status_code, login.reason))
self._session = session resp_json = login.json()
if user == self.test_login(): if resp_json['status'] != 'ok':
self.username = user if 'message' in resp_json:
raise ConnectionException("Login error: \"{}\" status, message \"{}\".".format(resp_json['status'],
resp_json['message']))
else: else:
self.username = None raise ConnectionException("Login error: \"{}\" status.".format(resp_json['status']))
self._session = None if not resp_json['authenticated']:
raise BadCredentialsException('Login error! Check your credentials!') if resp_json['user']:
else: # '{"authenticated": false, "user": true, "status": "ok"}'
raise ConnectionException('Login error! Connection error!') raise BadCredentialsException('Login error: Wrong password.')
else:
# '{"authenticated": false, "user": false, "status": "ok"}'
# Raise InvalidArgumentException rather than BadCredentialException, because BadCredentialException
# triggers re-asking of password in Instaloader.interactive_login(), which makes no sense if the
# username is invalid.
raise InvalidArgumentException('Login error: User {} does not exist.'.format(user))
# '{"authenticated": true, "user": true, "userId": ..., "oneTapPrompt": false, "status": "ok"}'
session.headers.update({'X-CSRFToken': login.cookies['csrftoken']})
self._session = session
self.username = user
def _sleep(self): def _sleep(self):
"""Sleep a short time if self.sleep is set. Called before each request to instagram.com.""" """Sleep a short time if self.sleep is set. Called before each request to instagram.com."""