Created
May 19, 2019 20:21
-
-
Save cwells/0b7e824bbc7b714688238223fc8d8c1f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
SKYHOOK_SDK_KEY = '<your skyhook sdk key>' | |
SKYHOOK_URL = 'https://global.skyhookwireless.com/wps2/location' | |
UUID = '<generate using uuidgen>' | |
import time | |
import webbrowser | |
import gi | |
gi.require_version('NM', '1.0') | |
from gi.repository import NM, GLib, Gio | |
from skyhook import Skyhook | |
main_loop = GLib.MainLoop() | |
def callback_scan_complete(client, result): | |
get_location(get_access_points(wireless_device)) | |
main_loop.quit() | |
def scan_access_points(device): | |
device.request_scan_async(Gio.Cancellable(), callback_scan_complete) | |
def get_access_points(device): | |
def ssid_to_utf8(ap): | |
ssid = ap.get_ssid() | |
if not ssid: return "" | |
return NM.utils_ssid_to_utf8(ap.get_ssid().get_data()) | |
return [ | |
( ap.get_bssid().replace(':', ''), str(ap.get_strength()), ssid_to_utf8(ap) ) | |
for ap in device.get_access_points() | |
] | |
def get_location(access_points): | |
skyhook = Skyhook(SKYHOOK_SDK_KEY, SKYHOOK_URL) | |
location = skyhook.get_location(UUID, access_points) | |
if location: | |
webbrowser.open_new_tab(f"https://maps.google.com/maps?q={location['latitude']},{location['longitude']}") | |
else: | |
print("Unable to determine location.") | |
client = NM.Client.new(None) | |
connections = [ | |
c.get_uuid() | |
for c in client.get_connections() | |
] | |
wireless_device = [ | |
device | |
for device in client.get_devices() | |
if device.get_device_type() == NM.DeviceType.WIFI | |
and device.get_active_connection().get_uuid() | |
][0] | |
scan_access_points(wireless_device) | |
main_loop.run() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import requests | |
from lxml import etree, objectify | |
class Skyhook: | |
def __init__(self, skyhook_sdk_key, skyhook_url): | |
self.skyhook_sdk_key = skyhook_sdk_key | |
self.skyhook_url = skyhook_url | |
def __prepare_location_rq_xml(self, device_id, access_points): | |
if not access_points: return None | |
root = etree.Element("LocationRQ", xmlns="http://skyhookwireless.com/wps/2005", version="2.21") | |
root.set("street-address-lookup", "none"); | |
root.set("profiling", "true"); | |
auth_elm = etree.SubElement(root, "authentication", version="2.2") | |
key_elm = etree.SubElement(auth_elm, "key") | |
key_elm.set("key", self.skyhook_sdk_key); | |
key_elm.set("username", device_id); | |
for ap in access_points: | |
ap_elm = etree.SubElement(root, "access-point") | |
mac = etree.SubElement(ap_elm, "mac").text = ap[0] | |
ssid = etree.SubElement(ap_elm, "ssid").text = ap[2] | |
signal = etree.SubElement(ap_elm, "signal-strength").text = ap[1] | |
age = etree.SubElement(ap_elm, "age").text = str(0) | |
return etree.tostring(root); | |
def __parse_location_rs_xml(self, loc_rs_xml): | |
root_rs = objectify.fromstring(loc_rs_xml) | |
for elm in root_rs.getiterator(): | |
if not hasattr(elm.tag, 'find'): | |
continue | |
i = elm.tag.find('}') | |
if i >= 0: | |
elm.tag = elm.tag[i + 1:] | |
objectify.deannotate(root_rs, cleanup_namespaces=True) | |
coerce = { | |
'latitude' : float, | |
'longitude' : float, | |
'accuracy' : int | |
} | |
fix = {} | |
for elm in root_rs.iter(): | |
fix[elm.tag] = coerce.get(elm.tag, lambda e: e)(elm.text) | |
if len(fix) < 3: | |
return None | |
return fix | |
def get_location(self, device_id, access_points): | |
""" Get location of 'device_id' using list of wifi access-points. | |
device_id: unique id of device | |
access_points: array of wifi access-points in the following format: | |
[[mac, rssi, ssid], [mac, rssi, ssid]] | |
[['001a1ee99745', '-47', 'tp-wpa2'], ['001a1ee99744', '-47', 'tp-wpa']] | |
returns fix, format: {'latitude': 40.064514, 'longitude': -75.46025, 'accuracy': 136} | |
""" | |
if not access_points: return None | |
try: | |
ap_data = self.__prepare_location_rq_xml(device_id, access_points) | |
if not ap_data: | |
return | |
response = requests.post(self.skyhook_url, headers={ 'Content-Type': 'text/xml' }, data=ap_data) | |
return self.__parse_location_rs_xml(response.content) | |
except Exception as e: | |
print(e) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment