get_game_info.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/usr/bin/env python
  2. import json
  3. import os
  4. import requests
  5. import sys
  6. import getpass
  7. def post_credentials(session, username, password):
  8. # Credentials POSTing and tokens retrieval
  9. # POST https://secure.zwift.com/auth/realms/zwift/tokens/access/codes
  10. try:
  11. response = session.post(
  12. url="https://secure.zwift.com/auth/realms/zwift/protocol/openid-connect/token",
  13. headers={
  14. "Accept": "*/*",
  15. "Accept-Encoding": "gzip, deflate",
  16. "Connection": "keep-alive",
  17. "Content-Type": "application/x-www-form-urlencoded",
  18. "Host": "secure.zwift.com",
  19. "User-Agent": "Zwift/1.5 (iPhone; iOS 9.0.2; Scale/2.00)",
  20. "Accept-Language": "en-US;q=1",
  21. },
  22. data={
  23. "client_id": "Zwift_Mobile_Link",
  24. "username": username,
  25. "password": password,
  26. "grant_type": "password",
  27. },
  28. allow_redirects=False,
  29. verify=True,
  30. )
  31. if response.status_code != 200:
  32. print('Response HTTP Status Code: {status_code}'.format(
  33. status_code=response.status_code))
  34. print('Response HTTP Response Body: {content}'.format(
  35. content=response.content))
  36. json_dict = json.loads(response.content)
  37. return (json_dict["access_token"], json_dict["refresh_token"], json_dict["expires_in"])
  38. except requests.exceptions.RequestException as e:
  39. print('HTTP Request failed: %s' % e)
  40. except KeyError as e:
  41. print('Invalid uname and/or password')
  42. exit(-1)
  43. def get_game_info(session, access_token):
  44. try:
  45. response = session.get(
  46. url="https://us-or-rly101.zwift.com/api/game_info",
  47. headers={
  48. "Accept": "*/*",
  49. "Connection": "keep-alive",
  50. "Host": "us-or-rly101.zwift.com",
  51. "User-Agent": "Zwift/115 CFNetwork/758.0.2 Darwin/15.0.0",
  52. "Authorization": "Bearer %s" % access_token,
  53. "Accept-Language": "en-us",
  54. "Zwift-Api-Version": "2.6"
  55. },
  56. verify=True,
  57. )
  58. if response.status_code != 200:
  59. print('Response HTTP Status Code: {status_code}'.format(
  60. status_code=response.status_code))
  61. return response.content
  62. except requests.exceptions.RequestException as e:
  63. print('HTTP Request failed: %s' % e)
  64. def logout(session, refresh_token):
  65. # Logout
  66. # POST https://secure.zwift.com/auth/realms/zwift/tokens/logout
  67. try:
  68. response = session.post(
  69. url="https://secure.zwift.com/auth/realms/zwift/tokens/logout",
  70. headers={
  71. "Accept": "*/*",
  72. "Accept-Encoding": "gzip, deflate",
  73. "Connection": "keep-alive",
  74. "Content-Type": "application/x-www-form-urlencoded",
  75. "Host": "secure.zwift.com",
  76. "User-Agent": "Zwift/1.5 (iPhone; iOS 9.0.2; Scale/2.00)",
  77. "Accept-Language": "en-US;q=1",
  78. },
  79. data={
  80. "client_id": "Zwift_Mobile_Link",
  81. "refresh_token": refresh_token,
  82. },
  83. verify=True,
  84. )
  85. if response.status_code != 204:
  86. print('Response HTTP Status Code: {status_code}'.format(
  87. status_code=response.status_code))
  88. print('Response HTTP Response Body: {content}'.format(
  89. content=response.content))
  90. except requests.exceptions.RequestException as e:
  91. print('HTTP Request failed: %s' % e)
  92. def main(argv):
  93. username = input("Enter Zwift login (e-mail): ")
  94. if not sys.stdin.isatty(): # This terminal cannot support input without displaying text
  95. print(f'*WARNING* The current shell ({os.name}) cannot support hidden text entry.')
  96. print(f'Your password entry WILL BE VISIBLE.')
  97. print(f'If you are running a bash shell under windows, try executing this program via winpty:')
  98. print(f'>winpty python {argv[0]}')
  99. password = input("Enter password (will be shown):")
  100. else:
  101. password = getpass.getpass("Enter password: ")
  102. session = requests.session()
  103. access_token, refresh_token, expired_in = post_credentials(session, username, password)
  104. game_info = get_game_info(session, access_token).decode('utf-8')
  105. with open('../data/game_info.txt', 'wb') as f:
  106. f.write(game_info.encode('utf-8-sig'))
  107. logout(session, refresh_token)
  108. if __name__ == '__main__':
  109. try:
  110. main(sys.argv)
  111. except KeyboardInterrupt:
  112. pass
  113. except SystemExit as se:
  114. print("ERROR:", se)