├── .gitignore ├── .python-version ├── requirements.txt ├── images ├── map_screenshot.png └── console_screenshot.png ├── pyproject.toml ├── AppleWLoc.proto ├── readme.md ├── AppleWLoc_pb2.py ├── apple_bssid_locator.py └── uv.lock /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | protobuf==5.29.4 2 | requests>=2.32.3 3 | -------------------------------------------------------------------------------- /images/map_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkosancanin/apple_bssid_locator/HEAD/images/map_screenshot.png -------------------------------------------------------------------------------- /images/console_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkosancanin/apple_bssid_locator/HEAD/images/console_screenshot.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "apple-bssid-locator" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "protobuf==5.29.4", 9 | "requests>=2.32.3", 10 | ] 11 | -------------------------------------------------------------------------------- /AppleWLoc.proto: -------------------------------------------------------------------------------- 1 | message WifiDevice { 2 | required string bssid = 1; 3 | message Location { 4 | optional int64 latitude = 1; 5 | optional int64 longitude = 2; 6 | optional int64 unknown_value3 = 3; 7 | optional int64 unknown_value4 = 4; 8 | optional int64 unknown_value5 = 5; 9 | optional int64 unknown_value6 = 6; 10 | optional int64 unknown_value7 = 7; 11 | optional int64 unknown_value8 = 8; 12 | optional int64 unknown_value9 = 9; 13 | optional int64 unknown_value10 = 10; 14 | optional int64 unknown_value11 = 11; 15 | optional int64 unknown_value12 = 12; 16 | optional int64 unknown_value21 = 21; 17 | } 18 | optional Location location= 2; 19 | } 20 | 21 | message AppleWLoc { 22 | optional int64 unknown_value0 = 1; 23 | repeated WifiDevice wifi_devices = 2; 24 | optional int32 unknown_value1 = 3; 25 | optional int32 return_single_result = 4; 26 | optional string APIName = 5; 27 | } 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### Overview 2 | Simple python tool which finds the location of a wifi access point from its BSSID (Basic Service Set Identifier) which is the MAC address of the wifi access point and optionally displays the location on Google Maps. This is implemented by calling the Apple Location Services API. 3 | 4 | ### Instructions/Usage 5 | Install python dependencies by running `pip install -r requirements.txt`. 6 | 7 | To find the location of a bssid run the following `python apple_bssid_locator.py 34:DB:FD:43:E3:A1`. 8 | 9 | To find the location and display it on a map run the following `python apple_bssid_locator.py 34:DB:FD:43:E3:A1 --map`. 10 | 11 | ### Credits 12 | The implementation is based on https://github.com/hubert3/iSniff-GPS which in turn is based on work from the paper by François-Xavier Aguessy and Côme Demoustier (http://fxaguessy.fr/rapport-pfe-interception-ssl-analyse-donnees-localisation-smartphones/) 13 | 14 | ### Screenshots 15 | ![Console](https://raw.githubusercontent.com/darkosancanin/apple_bssid_locator/master/images/console_screenshot.png) 16 | 17 | ![Map](https://raw.githubusercontent.com/darkosancanin/apple_bssid_locator/master/images/map_screenshot.png) -------------------------------------------------------------------------------- /AppleWLoc_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: AppleWLoc.proto 5 | # Protobuf Python Version: 5.29.4 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 29, 16 | 4, 17 | '', 18 | 'AppleWLoc.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | 26 | 27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x41ppleWLoc.proto\"\x81\x03\n\nWifiDevice\x12\r\n\x05\x62ssid\x18\x01 \x02(\t\x12&\n\x08location\x18\x02 \x01(\x0b\x32\x14.WifiDevice.Location\x1a\xbb\x02\n\x08Location\x12\x10\n\x08latitude\x18\x01 \x01(\x03\x12\x11\n\tlongitude\x18\x02 \x01(\x03\x12\x16\n\x0eunknown_value3\x18\x03 \x01(\x03\x12\x16\n\x0eunknown_value4\x18\x04 \x01(\x03\x12\x16\n\x0eunknown_value5\x18\x05 \x01(\x03\x12\x16\n\x0eunknown_value6\x18\x06 \x01(\x03\x12\x16\n\x0eunknown_value7\x18\x07 \x01(\x03\x12\x16\n\x0eunknown_value8\x18\x08 \x01(\x03\x12\x16\n\x0eunknown_value9\x18\t \x01(\x03\x12\x17\n\x0funknown_value10\x18\n \x01(\x03\x12\x17\n\x0funknown_value11\x18\x0b \x01(\x03\x12\x17\n\x0funknown_value12\x18\x0c \x01(\x03\x12\x17\n\x0funknown_value21\x18\x15 \x01(\x03\"\x8d\x01\n\tAppleWLoc\x12\x16\n\x0eunknown_value0\x18\x01 \x01(\x03\x12!\n\x0cwifi_devices\x18\x02 \x03(\x0b\x32\x0b.WifiDevice\x12\x16\n\x0eunknown_value1\x18\x03 \x01(\x05\x12\x1c\n\x14return_single_result\x18\x04 \x01(\x05\x12\x0f\n\x07\x41PIName\x18\x05 \x01(\t') 28 | 29 | _globals = globals() 30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'AppleWLoc_pb2', _globals) 32 | if not _descriptor._USE_C_DESCRIPTORS: 33 | DESCRIPTOR._loaded_options = None 34 | _globals['_WIFIDEVICE']._serialized_start=20 35 | _globals['_WIFIDEVICE']._serialized_end=405 36 | _globals['_WIFIDEVICE_LOCATION']._serialized_start=90 37 | _globals['_WIFIDEVICE_LOCATION']._serialized_end=405 38 | _globals['_APPLEWLOC']._serialized_start=408 39 | _globals['_APPLEWLOC']._serialized_end=549 40 | # @@protoc_insertion_point(module_scope) 41 | -------------------------------------------------------------------------------- /apple_bssid_locator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S uv run --script 2 | # -*- coding: utf-8 -*- 3 | 4 | # Implementation based on https://github.com/hubert3/iSniff-GPS which in turn is based on work from the paper by François-Xavier Aguessy and Côme Demoustier (http://fxaguessy.fr/rapport-pfe-interception-ssl-analyse-donnees-localisation-smartphones/) 5 | # Usage: apple_bssid_locator.py 34:DB:FD:43:E3:A1 --map 6 | 7 | import argparse 8 | import sys 9 | import code 10 | import requests 11 | import webbrowser 12 | import AppleWLoc_pb2 13 | 14 | def parse_arguments(): 15 | parser = argparse.ArgumentParser() 16 | parser.add_argument("bssid", type=str, help="display the location of the bssid") 17 | parser.add_argument("-m", "--map", help="shows the location on google maps", action='store_true') 18 | parser.add_argument("-a", "--all", help="shows all results returned, not just the requested one", action='store_true') 19 | args = parser.parse_args() 20 | return args 21 | 22 | def format_bssid(bssid): 23 | return ':'.join(e.rjust(2, '0') for e in bssid.split(':')) 24 | 25 | def process_result(apple_wloc): 26 | device_locations = {} 27 | for wifi_device in apple_wloc.wifi_devices: 28 | if wifi_device.HasField('location'): 29 | lat = wifi_device.location.latitude * 1e-8 30 | lon = wifi_device.location.longitude * 1e-8 31 | mac = format_bssid(wifi_device.bssid) 32 | device_locations[mac] = (lat,lon) 33 | return device_locations 34 | 35 | def query_bssid(bssid): 36 | apple_wloc = AppleWLoc_pb2.AppleWLoc() 37 | wifi_device = apple_wloc.wifi_devices.add() 38 | wifi_device.bssid = bssid 39 | apple_wloc.unknown_value1 = 0 40 | apple_wloc.return_single_result = 1 41 | serialized_apple_wloc = apple_wloc.SerializeToString() 42 | length_serialized_apple_wloc = len(serialized_apple_wloc) 43 | # Latest versions of the UA string are at https://user-agents.net/applications/cfnetwork/platforms/ios 44 | headers = {'User-Agent':'locationd/1753.17 CFNetwork/889.9 Darwin/17.2.0'} 45 | data = b"\x00\x01\x00\x05"+b"en_US"+b"\x00\x13"+b"com.apple.locationd"+b"\x00\x0a"+b"8.1.12B411"+b"\x00\x00\x00\x01\x00\x00\x00" + bytes((length_serialized_apple_wloc,)) + serialized_apple_wloc; 46 | r = requests.post('https://gs-loc.apple.com/clls/wloc', headers=headers, data=data) # CN of cert on this hostname is sometimes *.ls.apple.com / ls.apple.com, so have to disable SSL verify 47 | apple_wloc = AppleWLoc_pb2.AppleWLoc() 48 | apple_wloc.ParseFromString(r.content[10:]) 49 | return process_result(apple_wloc) 50 | 51 | def main(): 52 | args = parse_arguments() 53 | #requests.packages.urllib3.disable_warnings() 54 | print("Searching for location of bssid: %s" % args.bssid) 55 | results = query_bssid(args.bssid) 56 | 57 | # Determine which BSSIDs to process 58 | bssids_to_process = results.keys() if args.all else [args.bssid.lower()] 59 | 60 | found = False 61 | for bssid in bssids_to_process: 62 | if bssid in results: 63 | lat, lon = results[bssid] 64 | if lat == -180.0 and lon == -180.0: 65 | continue # Skip entries that were not found 66 | lat_str = str(lat) 67 | lon_str = str(lon) 68 | if found: print() 69 | print(f"BSSID: {bssid}") 70 | print(f"Latitude: {lat_str}") 71 | print(f"Longitude: {lon_str}") 72 | if args.map: 73 | url = f"http://www.google.com/maps/place/{lat_str},{lon_str}" 74 | webbrowser.open(url) 75 | found = True 76 | 77 | if not found: 78 | print("The bssid was not found.") 79 | 80 | if __name__ == '__main__': 81 | main() 82 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 1 3 | requires-python = ">=3.12" 4 | 5 | [[package]] 6 | name = "apple-bssid-locator" 7 | version = "0.1.0" 8 | source = { virtual = "." } 9 | dependencies = [ 10 | { name = "protobuf" }, 11 | { name = "requests" }, 12 | ] 13 | 14 | [package.metadata] 15 | requires-dist = [ 16 | { name = "protobuf", specifier = "==5.29.4" }, 17 | { name = "requests", specifier = ">=2.32.3" }, 18 | ] 19 | 20 | [[package]] 21 | name = "certifi" 22 | version = "2025.4.26" 23 | source = { registry = "https://pypi.org/simple" } 24 | sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705 } 25 | wheels = [ 26 | { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618 }, 27 | ] 28 | 29 | [[package]] 30 | name = "charset-normalizer" 31 | version = "3.4.2" 32 | source = { registry = "https://pypi.org/simple" } 33 | sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367 } 34 | wheels = [ 35 | { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936 }, 36 | { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790 }, 37 | { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924 }, 38 | { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626 }, 39 | { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567 }, 40 | { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957 }, 41 | { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408 }, 42 | { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399 }, 43 | { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815 }, 44 | { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537 }, 45 | { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565 }, 46 | { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357 }, 47 | { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776 }, 48 | { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622 }, 49 | { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435 }, 50 | { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653 }, 51 | { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231 }, 52 | { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243 }, 53 | { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442 }, 54 | { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147 }, 55 | { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057 }, 56 | { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454 }, 57 | { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174 }, 58 | { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166 }, 59 | { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064 }, 60 | { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641 }, 61 | { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626 }, 62 | ] 63 | 64 | [[package]] 65 | name = "idna" 66 | version = "3.10" 67 | source = { registry = "https://pypi.org/simple" } 68 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 69 | wheels = [ 70 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 71 | ] 72 | 73 | [[package]] 74 | name = "protobuf" 75 | version = "5.29.4" 76 | source = { registry = "https://pypi.org/simple" } 77 | sdist = { url = "https://files.pythonhosted.org/packages/17/7d/b9dca7365f0e2c4fa7c193ff795427cfa6290147e5185ab11ece280a18e7/protobuf-5.29.4.tar.gz", hash = "sha256:4f1dfcd7997b31ef8f53ec82781ff434a28bf71d9102ddde14d076adcfc78c99", size = 424902 } 78 | wheels = [ 79 | { url = "https://files.pythonhosted.org/packages/9a/b2/043a1a1a20edd134563699b0e91862726a0dc9146c090743b6c44d798e75/protobuf-5.29.4-cp310-abi3-win32.whl", hash = "sha256:13eb236f8eb9ec34e63fc8b1d6efd2777d062fa6aaa68268fb67cf77f6839ad7", size = 422709 }, 80 | { url = "https://files.pythonhosted.org/packages/79/fc/2474b59570daa818de6124c0a15741ee3e5d6302e9d6ce0bdfd12e98119f/protobuf-5.29.4-cp310-abi3-win_amd64.whl", hash = "sha256:bcefcdf3976233f8a502d265eb65ea740c989bacc6c30a58290ed0e519eb4b8d", size = 434506 }, 81 | { url = "https://files.pythonhosted.org/packages/46/de/7c126bbb06aa0f8a7b38aaf8bd746c514d70e6a2a3f6dd460b3b7aad7aae/protobuf-5.29.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:307ecba1d852ec237e9ba668e087326a67564ef83e45a0189a772ede9e854dd0", size = 417826 }, 82 | { url = "https://files.pythonhosted.org/packages/a2/b5/bade14ae31ba871a139aa45e7a8183d869efe87c34a4850c87b936963261/protobuf-5.29.4-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:aec4962f9ea93c431d5714ed1be1c93f13e1a8618e70035ba2b0564d9e633f2e", size = 319574 }, 83 | { url = "https://files.pythonhosted.org/packages/46/88/b01ed2291aae68b708f7d334288ad5fb3e7aa769a9c309c91a0d55cb91b0/protobuf-5.29.4-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:d7d3f7d1d5a66ed4942d4fefb12ac4b14a29028b209d4bfb25c68ae172059922", size = 319672 }, 84 | { url = "https://files.pythonhosted.org/packages/12/fb/a586e0c973c95502e054ac5f81f88394f24ccc7982dac19c515acd9e2c93/protobuf-5.29.4-py3-none-any.whl", hash = "sha256:3fde11b505e1597f71b875ef2fc52062b6a9740e5f7c8997ce878b6009145862", size = 172551 }, 85 | ] 86 | 87 | [[package]] 88 | name = "requests" 89 | version = "2.32.3" 90 | source = { registry = "https://pypi.org/simple" } 91 | dependencies = [ 92 | { name = "certifi" }, 93 | { name = "charset-normalizer" }, 94 | { name = "idna" }, 95 | { name = "urllib3" }, 96 | ] 97 | sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } 98 | wheels = [ 99 | { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, 100 | ] 101 | 102 | [[package]] 103 | name = "urllib3" 104 | version = "2.4.0" 105 | source = { registry = "https://pypi.org/simple" } 106 | sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672 } 107 | wheels = [ 108 | { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680 }, 109 | ] 110 | --------------------------------------------------------------------------------