auth.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import codecs
  2. import datetime
  3. import json
  4. import os.path
  5. import sys
  6. import traceback
  7. try:
  8. import logger
  9. import helpers
  10. import pil
  11. except ImportError:
  12. from . import logger
  13. from . import helpers
  14. from . import pil
  15. try:
  16. from instagram_private_api import (
  17. Client, ClientError, ClientLoginError,
  18. ClientCookieExpiredError,
  19. ClientTwoFactorRequiredError)
  20. except ImportError:
  21. sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
  22. from instagram_private_api import (
  23. Client, ClientError, ClientLoginError,
  24. ClientCookieExpiredError,
  25. ClientTwoFactorRequiredError)
  26. def to_json(python_object):
  27. if isinstance(python_object, bytes):
  28. return {'__class__': 'bytes',
  29. '__value__': codecs.encode(python_object, 'base64').decode()}
  30. raise TypeError(repr(python_object) + ' is not JSON serializable')
  31. def from_json(json_object):
  32. if '__class__' in json_object and json_object.get('__class__') == 'bytes':
  33. return codecs.decode(json_object.get('__value__').encode(), 'base64')
  34. return json_object
  35. def onlogin_callback(api, cookie_file):
  36. cache_settings = api.settings
  37. with open(cookie_file, 'w') as outfile:
  38. json.dump(cache_settings, outfile, default=to_json)
  39. logger.info('New cookie file was made: {0!s}'.format(os.path.basename(cookie_file)))
  40. logger.separator()
  41. def authenticate(username, password, force_use_login_args=False):
  42. ig_api = None
  43. try:
  44. if force_use_login_args:
  45. pil.ig_user = username
  46. pil.ig_pass = password
  47. pil.config_login_overridden = True
  48. logger.binfo("Overriding configuration file login with -u and -p arguments.")
  49. logger.separator()
  50. cookie_file = os.path.join(os.path.dirname(pil.config_path), "{}.json".format(username))
  51. if not os.path.isfile(cookie_file):
  52. # settings file does not exist
  53. logger.warn('Unable to find cookie file: {0!s}'.format(os.path.basename(cookie_file)))
  54. logger.info('Creating a new one.')
  55. # login new
  56. ig_api = Client(
  57. username, password,
  58. on_login=lambda x: onlogin_callback(x, cookie_file), proxy=pil.proxy)
  59. try:
  60. ig_api.login()
  61. except ClientTwoFactorRequiredError as e:
  62. response = json.loads(e.error_response)
  63. two_factor_info = response['two_factor_info']
  64. two_factor_identifier = two_factor_info['two_factor_identifier']
  65. if two_factor_info['totp_two_factor_on']:
  66. code_device = 'one-time password app'
  67. else:
  68. code_device = 'number ending with {}'.format(two_factor_info['obfuscated_phone_number'])
  69. verification_code = input('Enter verification code, sent to {}: '.format(code_device))
  70. try:
  71. ig_api.login2fa(two_factor_identifier, verification_code)
  72. except ClientError as e:
  73. print(e.error_response)
  74. else:
  75. with open(cookie_file) as file_data:
  76. cached_settings = json.load(file_data, object_hook=from_json)
  77. # logger.info('Using settings file: {0!s}'.format(cookie_file))
  78. device_id = cached_settings.get('device_id')
  79. # reuse auth cached_settings
  80. try:
  81. ig_api = Client(
  82. username, password,
  83. settings=cached_settings, proxy=pil.proxy)
  84. except ClientCookieExpiredError as e:
  85. logger.warn('The current cookie file has expired, creating a new one.')
  86. ig_api = Client(
  87. username, password,
  88. device_id=device_id,
  89. on_login=lambda x: onlogin_callback(x, cookie_file), proxy=pil.proxy)
  90. except (ClientLoginError, ClientError) as e:
  91. logger.separator()
  92. logger.error('Could not login: {:s}'.format(e.error_response))
  93. # logger.error('{:s}'.format(json.loads(e.error_response).get("message", e.error_response)))
  94. # logger.error('{:s}'.format(e.error_response))
  95. logger.separator()
  96. except Exception as e:
  97. if str(e).startswith("unsupported pickle protocol"):
  98. logger.warn("This cookie file is not compatible with Python {}.".format(sys.version.split(' ')[0][0]))
  99. logger.warn("Please delete your cookie file '{}.json' and try again.".format(username))
  100. else:
  101. logger.separator()
  102. logger.error('Unexpected exception: {:s}'.format(e))
  103. logger.separator()
  104. except KeyboardInterrupt:
  105. logger.separator()
  106. logger.warn("The user authentication has been aborted.")
  107. logger.separator()
  108. if ig_api:
  109. logger.info('Successfully logged into account: {:s}'.format(str(ig_api.authenticated_user_name)))
  110. if pil.show_cookie_expiry and not force_use_login_args:
  111. try:
  112. cookie_expiry = ig_api.cookie_jar.auth_expires
  113. logger.info('Cookie file expiry date: {:s}'.format(
  114. datetime.datetime.fromtimestamp(cookie_expiry).strftime('%Y-%m-%d at %I:%M:%S %p')))
  115. except Exception as e:
  116. logger.warn('An error occurred while getting the cookie file expiry date: {:s}'.format(str(e)))
  117. logger.separator()
  118. return ig_api
  119. else:
  120. return None