gpsoauth-0.4.1/0000775000175100017510000000000013052107112013636 5ustar simonsimon00000000000000gpsoauth-0.4.1/setup.py0000664000175100017510000000271713052106751015367 0ustar simonsimon00000000000000import re try: from setuptools import setup except ImportError: from distutils.core import setup with open('README.rst') as f: readme = f.read() # This hack is from http://stackoverflow.com/a/7071358/1231454; # the version is kept in a seperate file and gets parsed - this # way, setup.py doesn't have to import the package. VERSIONFILE = 'gpsoauth/_version.py' version_line = open(VERSIONFILE).read() version_re = r"^__version__ = ['\"]([^'\"]*)['\"]" match = re.search(version_re, version_line, re.M) if match: version = match.group(1) else: raise RuntimeError("Could not find version in '%s'" % VERSIONFILE) setup( name='gpsoauth', version=version, description='A python client library for Google Play Services OAuth.', long_description=readme, author='Simon Weber', author_email='simon@simonmweber.com', url='https://github.com/simon-weber/gpsoauth', packages=['gpsoauth'], include_package_data=True, install_requires=[ 'pycryptodomex >= 3.0', 'requests', ], license='MIT', zip_safe=False, classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', ], ) gpsoauth-0.4.1/gpsoauth/0000775000175100017510000000000013052107112015470 5ustar simonsimon00000000000000gpsoauth-0.4.1/gpsoauth/tests.py0000664000175100017510000000066312724712352017226 0ustar simonsimon00000000000000from gpsoauth.google import signature from gpsoauth.util import bytes_to_long, long_to_bytes from gpsoauth import android_key_7_3_29, b64_key_7_3_29 def test_static_signature(): username = "someone@google.com" password = "apassword" assert signature(username, password, android_key_7_3_29).startswith(b"AFcb4K") def test_conversion_roundtrip(): assert long_to_bytes(bytes_to_long(b64_key_7_3_29)) == b64_key_7_3_29 gpsoauth-0.4.1/gpsoauth/util.py0000664000175100017510000000204312724712352017033 0ustar simonsimon00000000000000import binascii import sys PY3 = sys.version[0] == '3' def bytes_to_long(s): if PY3: return int.from_bytes(s, "big") return long(s.encode('hex'), 16) def long_to_bytes(lnum, padmultiple=1): """Packs the lnum (which must be convertable to a long) into a byte string 0 padded to a multiple of padmultiple bytes in size. 0 means no padding whatsoever, so that packing 0 result in an empty string. The resulting byte string is the big-endian two's complement representation of the passed in long.""" # source: http://stackoverflow.com/a/14527004/1231454 if lnum == 0: return b'\0' * padmultiple elif lnum < 0: raise ValueError("Can only convert non-negative numbers.") s = hex(lnum)[2:] s = s.rstrip('L') if len(s) & 1: s = '0' + s s = binascii.unhexlify(s) if (padmultiple != 1) and (padmultiple != 0): filled_so_far = len(s) % padmultiple if filled_so_far != 0: s = b'\0' * (padmultiple - filled_so_far) + s return s gpsoauth-0.4.1/gpsoauth/_version.py0000664000175100017510000000002613052107070017667 0ustar simonsimon00000000000000__version__ = '0.4.1' gpsoauth-0.4.1/gpsoauth/google.py0000664000175100017510000000231212724712352017331 0ustar simonsimon00000000000000import base64 import hashlib from Cryptodome.PublicKey import RSA from Cryptodome.Cipher import PKCS1_OAEP from .util import bytes_to_long, long_to_bytes def key_from_b64(b64_key): binaryKey = base64.b64decode(b64_key) i = bytes_to_long(binaryKey[:4]) mod = bytes_to_long(binaryKey[4:4+i]) j = bytes_to_long(binaryKey[i+4:i+4+4]) exponent = bytes_to_long(binaryKey[i+8:i+8+j]) key = RSA.construct((mod, exponent)) return key def key_to_struct(key): mod = long_to_bytes(key.n) exponent = long_to_bytes(key.e) return b'\x00\x00\x00\x80' + mod + b'\x00\x00\x00\x03' + exponent def parse_auth_response(text): response_data = {} for line in text.split('\n'): if not line: continue key, _, val = line.partition('=') response_data[key] = val return response_data def signature(email, password, key): signature = bytearray(b'\x00') struct = key_to_struct(key) signature.extend(hashlib.sha1(struct).digest()[:4]) cipher = PKCS1_OAEP.new(key) encrypted_login = cipher.encrypt((email + u'\x00' + password).encode('utf-8')) signature.extend(encrypted_login) return base64.urlsafe_b64encode(signature) gpsoauth-0.4.1/gpsoauth/__init__.py0000664000175100017510000000630512756155621017627 0ustar simonsimon00000000000000import requests from ._version import __version__ from . import google # The key is distirbuted with Google Play Services. # This one is from version 7.3.29. b64_key_7_3_29 = (b"AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3" b"iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pK" b"RI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0QRNVz34kMJR3P/LgHax/" b"6rmf5AAAAAwEAAQ==") android_key_7_3_29 = google.key_from_b64(b64_key_7_3_29) auth_url = 'https://android.clients.google.com/auth' useragent = 'gpsoauth/' + __version__ def _perform_auth_request(data, proxy=None): session = requests.session() if proxy: session.proxies = proxy res = session.post(auth_url, data, headers={'User-Agent': useragent}) return google.parse_auth_response(res.text) def perform_master_login(email, password, android_id, service='ac2dm', device_country='us', operatorCountry='us', lang='en', sdk_version=17, proxy=None): """ Perform a master login, which is what Android does when you first add a Google account. Return a dict, eg:: { 'Auth': '...', 'Email': 'email@gmail.com', 'GooglePlusUpgrade': '1', 'LSID': '...', 'PicasaUser': 'My Name', 'RopRevision': '1', 'RopText': ' ', 'SID': '...', 'Token': 'oauth2rt_1/...', 'firstName': 'My', 'lastName': 'Name', 'services': 'hist,mail,googleme,...' } """ data = { 'accountType': 'HOSTED_OR_GOOGLE', 'Email': email, 'has_permission': 1, 'add_account': 1, 'EncryptedPasswd': google.signature(email, password, android_key_7_3_29), 'service': service, 'source': 'android', 'androidId': android_id, 'device_country': device_country, 'operatorCountry': device_country, 'lang': lang, 'sdk_version': sdk_version } return _perform_auth_request(data, proxy) def perform_oauth(email, master_token, android_id, service, app, client_sig, device_country='us', operatorCountry='us', lang='en', sdk_version=17, proxy=None): """ Use a master token from master_login to perform OAuth to a specific Google service. Return a dict, eg:: { 'Auth': '...', 'LSID': '...', 'SID': '..', 'issueAdvice': 'auto', 'services': 'hist,mail,googleme,...' } To authenticate requests to this service, include a header ``Authorization: GoogleLogin auth=res['Auth']``. """ data = { 'accountType': 'HOSTED_OR_GOOGLE', 'Email': email, 'has_permission': 1, 'EncryptedPasswd': master_token, 'service': service, 'source': 'android', 'androidId': android_id, 'app': app, 'client_sig': client_sig, 'device_country': device_country, 'operatorCountry': device_country, 'lang': lang, 'sdk_version': sdk_version } return _perform_auth_request(data, proxy) gpsoauth-0.4.1/PKG-INFO0000664000175100017510000000265713052107112014745 0ustar simonsimon00000000000000Metadata-Version: 1.1 Name: gpsoauth Version: 0.4.1 Summary: A python client library for Google Play Services OAuth. Home-page: https://github.com/simon-weber/gpsoauth Author: Simon Weber Author-email: simon@simonmweber.com License: MIT Description: gpsoauth: a python client library for Google Play Services OAuth ================================================================ gpsoauth allows python code to use the "master token" flow that KB Sriram described at http://sbktech.blogspot.com/2014/01/inside-android-play-services-magic.html. This can be useful when writing code that poses as a Google app, like `gmusicapi `__ does. Many thanks to Dima Kovalenko for reverse engieering the EncryptedPasswd signature in http://codedigging.com/blog/2014-06-09-about-encryptedpasswd. Ports ----- * C#: https://github.com/vemacs/GPSOAuthSharp. * Ruby: https://github.com/bryanmytko/gpsoauth Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 gpsoauth-0.4.1/setup.cfg0000664000175100017510000000004613052107112015457 0ustar simonsimon00000000000000[egg_info] tag_build = tag_date = 0 gpsoauth-0.4.1/gpsoauth.egg-info/0000775000175100017510000000000013052107112017162 5ustar simonsimon00000000000000gpsoauth-0.4.1/gpsoauth.egg-info/dependency_links.txt0000664000175100017510000000000113052107112023230 0ustar simonsimon00000000000000 gpsoauth-0.4.1/gpsoauth.egg-info/top_level.txt0000664000175100017510000000001113052107112021704 0ustar simonsimon00000000000000gpsoauth gpsoauth-0.4.1/gpsoauth.egg-info/PKG-INFO0000664000175100017510000000265713052107112020271 0ustar simonsimon00000000000000Metadata-Version: 1.1 Name: gpsoauth Version: 0.4.1 Summary: A python client library for Google Play Services OAuth. Home-page: https://github.com/simon-weber/gpsoauth Author: Simon Weber Author-email: simon@simonmweber.com License: MIT Description: gpsoauth: a python client library for Google Play Services OAuth ================================================================ gpsoauth allows python code to use the "master token" flow that KB Sriram described at http://sbktech.blogspot.com/2014/01/inside-android-play-services-magic.html. This can be useful when writing code that poses as a Google app, like `gmusicapi `__ does. Many thanks to Dima Kovalenko for reverse engieering the EncryptedPasswd signature in http://codedigging.com/blog/2014-06-09-about-encryptedpasswd. Ports ----- * C#: https://github.com/vemacs/GPSOAuthSharp. * Ruby: https://github.com/bryanmytko/gpsoauth Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 gpsoauth-0.4.1/gpsoauth.egg-info/SOURCES.txt0000664000175100017510000000046113052107112021047 0ustar simonsimon00000000000000README.rst setup.py gpsoauth/__init__.py gpsoauth/_version.py gpsoauth/google.py gpsoauth/tests.py gpsoauth/util.py gpsoauth.egg-info/PKG-INFO gpsoauth.egg-info/SOURCES.txt gpsoauth.egg-info/dependency_links.txt gpsoauth.egg-info/not-zip-safe gpsoauth.egg-info/requires.txt gpsoauth.egg-info/top_level.txtgpsoauth-0.4.1/gpsoauth.egg-info/not-zip-safe0000664000175100017510000000000112724712500021420 0ustar simonsimon00000000000000 gpsoauth-0.4.1/gpsoauth.egg-info/requires.txt0000664000175100017510000000003613052107112021561 0ustar simonsimon00000000000000pycryptodomex >= 3.0 requests gpsoauth-0.4.1/README.rst0000664000175100017510000000127712756155621015356 0ustar simonsimon00000000000000gpsoauth: a python client library for Google Play Services OAuth ================================================================ gpsoauth allows python code to use the "master token" flow that KB Sriram described at http://sbktech.blogspot.com/2014/01/inside-android-play-services-magic.html. This can be useful when writing code that poses as a Google app, like `gmusicapi `__ does. Many thanks to Dima Kovalenko for reverse engieering the EncryptedPasswd signature in http://codedigging.com/blog/2014-06-09-about-encryptedpasswd. Ports ----- * C#: https://github.com/vemacs/GPSOAuthSharp. * Ruby: https://github.com/bryanmytko/gpsoauth