-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #139 from prey/rebased-location
Add native geolocation as main geoloc strategy.
- Loading branch information
Showing
23 changed files
with
1,340 additions
and
187 deletions.
There are no files selected for viewing
This file contains 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
Binary file not shown.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
var join = require('path').join, | ||
child_process = require('child_process'), | ||
common = require('../../../common'), | ||
system = common.system, | ||
gte = common.helpers.is_greater_or_equal; | ||
|
||
// whereami bin from https://github.com/robmathers/WhereAmI | ||
var bin = join(__dirname, 'bin', 'whereami'); | ||
|
||
var get_using_corelocation = function(cb) { | ||
child_process.exec(bin, function(err, out) { | ||
if (err) return cb(err); | ||
|
||
if (!out.toString().match('Latitude')) | ||
return cb(new Error('Unable to get geoposition data using CoreLocation.')); | ||
|
||
var match, str = out.toString(); | ||
|
||
var res = { | ||
lat: str.match(/Latitude: (.+)/)[1], | ||
lng: str.match(/Longitude: (.+)/)[1] | ||
} | ||
|
||
if (match = str.match(/\nAccuracy.*: (.+)/)) { | ||
res.accuracy = match[1]; | ||
} else if (match = str.match(/Horizontal Accuracy.*: (.+)/)) { | ||
res.accuracy = match[1]; | ||
res.vertical_accuracy = str.match(/Vertical Accuracy.*: (.+)/)[1]; | ||
res.altitude = str.match(/Altitude.*: (.+)/)[1]; | ||
} | ||
|
||
cb(null, res); | ||
}); | ||
} | ||
|
||
exports.get_location = function(cb) { | ||
system.get_os_version(function(err, version) { | ||
if (version && gte(version, "10.6.0")) | ||
return get_using_corelocation(cb); | ||
|
||
cb(new Error('CoreLocation not suppored in OSX ' + version)) | ||
}); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,41 @@ | ||
"use strict"; | ||
|
||
////////////////////////////////////////// | ||
// Prey JS Geo Module | ||
// (c) 2011 - Fork Ltd. | ||
// by Tomas Pollak - http://forkhq.com | ||
// GPLv3 Licensed | ||
////////////////////////////////////////// | ||
var strategies = require('./strategies'), | ||
logger = require('../../common').logger.prefix('geo'); | ||
|
||
var client = require('needle'), | ||
get_agent = require('random-ua').generate, | ||
providers = require('./../../providers'); | ||
function log_error(err, strategy) { | ||
logger.debug("Error getting location using " + strategy + " strategy: " + err); | ||
} | ||
|
||
var process_response = function(body, cb){ | ||
var coords; | ||
exports.get_location = function(cb) { | ||
|
||
if (typeof body === 'object') { | ||
coords = body; | ||
} else { | ||
try { | ||
coords = JSON.parse(body); | ||
} catch(e) { | ||
return cb(e); | ||
} | ||
} | ||
|
||
if (!coords.location || (!coords.location.lat && !coords.location.latitude)) | ||
return cb(new Error("Couldn't get any geoposition data. Try moving around a bit.")); | ||
|
||
var data = { | ||
lat: coords.location.lat || coords.location.latitude, | ||
lng: coords.location.lng || coords.location.longitude, | ||
accuracy: coords.accuracy || coords.location.accuracy, | ||
method: 'wifi' | ||
}; | ||
|
||
cb(null, data); | ||
}; | ||
|
||
|
||
exports.send_data = function(list, cb){ | ||
|
||
var aps = []; | ||
strategies.native(native_cb); | ||
|
||
list.slice(0, 30).forEach(function(ap){ | ||
var str = 'wifi=mac:' + ap.mac_address + '|ssid:' + encodeURIComponent(ap.ssid); | ||
str += '|ss:' + ap.signal_strength; | ||
aps.push(str); | ||
}); | ||
|
||
var opts = { user_agent: get_agent() }, | ||
url = 'https://maps.googleapis.com/maps/api/browserlocation/json?', | ||
query = url + 'browser=true&sensor=true&' + aps.join('&'); | ||
function native_cb(err, res) { | ||
if (err) { | ||
log_error(err, "native"); | ||
return strategies.google(google_cb); | ||
} | ||
|
||
client.get(query, opts, function(err, resp, body) { | ||
if (err) return cb(err); | ||
process_response(body, cb); | ||
}); | ||
return cb(null, res); | ||
} | ||
|
||
}; | ||
function google_cb(err, res) { | ||
if (err) { | ||
log_error(err, "google"); | ||
return strategies.geoip(geoip_cb); | ||
} | ||
|
||
exports.get_location = function(callback){ | ||
return cb(null, res); | ||
} | ||
|
||
providers.get('access_points_list', function(err, list) { | ||
if (err) return callback(err); | ||
function geoip_cb(err, res) { | ||
if (err) { | ||
log_error(err, "geoip"); | ||
return cb(err); | ||
} | ||
|
||
exports.send_data(list, callback); | ||
}); | ||
return cb(null, res); | ||
} | ||
|
||
}; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// geolocation provider using geoclue service | ||
|
||
var exec = require('child_process').exec; | ||
|
||
/* | ||
valid dbus reply format: | ||
int32 # number of fields | ||
int32 # timestamp | ||
double # lat | ||
double # lng | ||
double # altitude | ||
struct { # accuracy | ||
int32 3 | ||
double 0 | ||
double 0 | ||
} | ||
*/ | ||
|
||
function parse(out, cb) { | ||
var matches = out.match(/double ([\d\.-]+)/g); | ||
if (matches < 2) | ||
return cb(new Error('Unable to get location.')) | ||
|
||
var res = { | ||
lat: parseFloat(matches[0].replace('double ', '')), | ||
lng: parseFloat(matches[1].replace('double ', '')), | ||
altitude: parseFloat(matches[2].replace('double ', '')) | ||
} | ||
|
||
cb(null, res); | ||
} | ||
|
||
function get_command_one(provider) { | ||
var bin = 'dbus-send', | ||
service = 'org.freedesktop.Geoclue.Providers.' + provider, | ||
path = '/org/freedesktop/Geoclue/Providers/' + provider, | ||
command = 'org.freedesktop.Geoclue.Position.GetPosition'; | ||
|
||
return [bin, '--print-reply', '--dest=' + service, path, command].join(' '); | ||
} | ||
|
||
function geoclue_one(provider, cb) { | ||
var cmd = get_command_one(provider); | ||
|
||
exec(cmd, function(err, out) { | ||
if (err) return cb(err); | ||
|
||
parse(out, cb); | ||
}) | ||
} | ||
|
||
function get_command_two() { | ||
var bin = 'dbus-send', | ||
service = 'org.freedesktop.GeoClue2', | ||
path = '/org/freedesktop/GeoClue2', | ||
command = 'org.freedesktop.GeoClue2.Location'; | ||
|
||
return [bin, '--print-reply', '--dest=' + service, path, command].join(' '); | ||
} | ||
|
||
function geoclue_two(cb) { | ||
exec(get_command_two, function(err, out) { | ||
if (err) return cb(err); | ||
|
||
parse(out, cb); | ||
}) | ||
} | ||
|
||
exports.get_location = function(cb) { | ||
geoclue_two(function(err, res) { | ||
if (res) return cb(null, res); | ||
|
||
geoclue_one('Skyhook', function(err, res) { | ||
if (res) return cb(null, res); | ||
|
||
geoclue_one('UbuntuGeoIP', cb); | ||
}); | ||
}) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
"use strict" | ||
|
||
var join = require('path').join, | ||
needle = require('needle'), | ||
get_agent = require('random-ua').generate, | ||
platform = require(join(__dirname, process.platform)), | ||
providers = require('./../../providers'), | ||
logger = require('../../common').logger.prefix('geo'); | ||
|
||
function geoip(cb) { | ||
logger.debug("Getting location via geoip"); | ||
|
||
needle.get('http://ipinfo.io/geo', function(err, resp, body) { | ||
if (!body || !body.loc) { | ||
return cb(err || new Error('Unable to get location from IP.')); | ||
} | ||
|
||
logger.debug("Got location via geoip"); | ||
|
||
var res = { | ||
lat: parseFloat(body.loc.split(',')[0]), | ||
lng: parseFloat(body.loc.split(',')[1]), | ||
method: 'geoip' | ||
} | ||
|
||
cb(null, res); | ||
}); | ||
} | ||
|
||
function google(cb) { | ||
logger.debug("Getting location via google api"); | ||
|
||
providers.get('access_points_list', function(err, list) { | ||
if (err) return cb(err); | ||
|
||
send_data(list, cb); | ||
}); | ||
|
||
function send_data(list, cb) { | ||
|
||
logger.debug("Sending AP data to Google API"); | ||
|
||
var aps = []; | ||
|
||
list.slice(0, 30).forEach(function(ap) { | ||
var str = 'wifi=mac:' + ap.mac_address + '|ssid:' + encodeURIComponent(ap.ssid); | ||
str += '|ss:' + ap.signal_strength; | ||
aps.push(str); | ||
}); | ||
|
||
var opts = { | ||
user_agent: get_agent() | ||
}, | ||
url = 'https://maps.googleapis.com/maps/api/browserlocation/json?', | ||
query = url + 'browser=true&sensor=true&' + aps.join('&'); | ||
|
||
needle.get(query, opts, function(err, resp, body) { | ||
if (err) return cb(err); | ||
process_response(body, cb); | ||
}); | ||
|
||
} | ||
|
||
function process_response(body, cb) { | ||
logger.debug("Processing Google API response"); | ||
|
||
var coords; | ||
|
||
if (typeof body === 'object') { | ||
coords = body; | ||
} else { | ||
try { | ||
coords = JSON.parse(body); | ||
} catch (e) { | ||
return cb(e); | ||
} | ||
} | ||
|
||
if (!coords.location || (!coords.location.lat && !coords.location.latitude)) | ||
return cb(new Error("Couldn't get any geoposition data. Try moving around a bit.")); | ||
|
||
logger.debug("Got location via Google API"); | ||
|
||
var data = { | ||
lat: coords.location.lat || coords.location.latitude, | ||
lng: coords.location.lng || coords.location.longitude, | ||
accuracy: coords.accuracy || coords.location.accuracy, | ||
method: 'wifi' | ||
}; | ||
|
||
return cb(null, data); | ||
} | ||
} | ||
|
||
function geonative(cb) { | ||
logger.debug("Getting location via native geoloc"); | ||
|
||
platform.get_location(function(err, res) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
|
||
logger.debug("Got location via native geoloc"); | ||
|
||
// Avoid adding property in each native geoloc implementation | ||
res.method = 'geonative'; | ||
|
||
return cb(null, res); | ||
}); | ||
} | ||
|
||
module.exports = { | ||
'geoip': geoip, | ||
'google': google, | ||
'native': geonative | ||
}; |
Oops, something went wrong.