geocoder 1.2.6 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +189 -1
- data/LICENSE +1 -1
- data/README.md +387 -755
- data/examples/autoexpire_cache_redis.rb +5 -3
- data/examples/reverse_geocode_job.rb +40 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +17 -16
- data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
- data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
- data/lib/generators/geocoder/migration_version.rb +15 -0
- data/lib/geocoder/cache.rb +6 -2
- data/lib/geocoder/calculations.rb +30 -38
- data/lib/geocoder/cli.rb +2 -2
- data/lib/geocoder/configuration.rb +18 -5
- data/lib/geocoder/esri_token.rb +38 -0
- data/lib/geocoder/exceptions.rb +19 -0
- data/lib/geocoder/ip_address.rb +16 -11
- data/lib/geocoder/kernel_logger.rb +25 -0
- data/lib/geocoder/logger.rb +47 -0
- data/lib/geocoder/lookup.rb +31 -12
- data/lib/geocoder/lookups/amap.rb +63 -0
- data/lib/geocoder/lookups/baidu.rb +17 -9
- data/lib/geocoder/lookups/baidu_ip.rb +7 -31
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
- data/lib/geocoder/lookups/base.rb +73 -25
- data/lib/geocoder/lookups/bing.rb +38 -15
- data/lib/geocoder/lookups/db_ip_com.rb +52 -0
- data/lib/geocoder/lookups/dstk.rb +4 -2
- data/lib/geocoder/lookups/esri.rb +55 -8
- data/lib/geocoder/lookups/freegeoip.rb +18 -5
- data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
- data/lib/geocoder/lookups/geocodio.rb +8 -8
- data/lib/geocoder/lookups/geoip2.rb +10 -5
- data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
- data/lib/geocoder/lookups/google.rb +37 -9
- data/lib/geocoder/lookups/google_places_details.rb +9 -9
- data/lib/geocoder/lookups/google_places_search.rb +33 -0
- data/lib/geocoder/lookups/google_premier.rb +11 -1
- data/lib/geocoder/lookups/here.rb +29 -23
- data/lib/geocoder/lookups/ip2location.rb +67 -0
- data/lib/geocoder/lookups/ipapi_com.rb +82 -0
- data/lib/geocoder/lookups/ipdata_co.rb +62 -0
- data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
- data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
- data/lib/geocoder/lookups/ipregistry.rb +68 -0
- data/lib/geocoder/lookups/ipstack.rb +63 -0
- data/lib/geocoder/lookups/latlon.rb +59 -0
- data/lib/geocoder/lookups/location_iq.rb +50 -0
- data/lib/geocoder/lookups/mapbox.rb +59 -0
- data/lib/geocoder/lookups/mapquest.rb +7 -9
- data/lib/geocoder/lookups/maxmind.rb +7 -7
- data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
- data/lib/geocoder/lookups/maxmind_local.rb +9 -2
- data/lib/geocoder/lookups/nominatim.rb +18 -6
- data/lib/geocoder/lookups/opencagedata.rb +16 -9
- data/lib/geocoder/lookups/osmnames.rb +57 -0
- data/lib/geocoder/lookups/pelias.rb +63 -0
- data/lib/geocoder/lookups/pickpoint.rb +41 -0
- data/lib/geocoder/lookups/pointpin.rb +14 -13
- data/lib/geocoder/lookups/postcode_anywhere_uk.rb +7 -8
- data/lib/geocoder/lookups/postcodes_io.rb +31 -0
- data/lib/geocoder/lookups/smarty_streets.rb +23 -5
- data/lib/geocoder/lookups/telize.rb +42 -7
- data/lib/geocoder/lookups/tencent.rb +59 -0
- data/lib/geocoder/lookups/yandex.rb +17 -9
- data/lib/geocoder/models/active_record.rb +4 -3
- data/lib/geocoder/models/mongo_base.rb +0 -2
- data/lib/geocoder/query.rb +15 -1
- data/lib/geocoder/railtie.rb +1 -1
- data/lib/geocoder/request.rb +103 -14
- data/lib/geocoder/results/amap.rb +87 -0
- data/lib/geocoder/results/baidu.rb +10 -14
- data/lib/geocoder/results/ban_data_gouv_fr.rb +257 -0
- data/lib/geocoder/results/base.rb +13 -1
- data/lib/geocoder/results/bing.rb +5 -1
- data/lib/geocoder/results/db_ip_com.rb +58 -0
- data/lib/geocoder/results/esri.rb +30 -6
- data/lib/geocoder/results/freegeoip.rb +2 -7
- data/lib/geocoder/results/geocoder_ca.rb +3 -3
- data/lib/geocoder/results/geocodio.rb +15 -3
- data/lib/geocoder/results/geoip2.rb +37 -25
- data/lib/geocoder/results/geoportail_lu.rb +71 -0
- data/lib/geocoder/results/google.rb +26 -0
- data/lib/geocoder/results/google_places_details.rb +4 -0
- data/lib/geocoder/results/google_places_search.rb +52 -0
- data/lib/geocoder/results/here.rb +21 -1
- data/lib/geocoder/results/ip2location.rb +22 -0
- data/lib/geocoder/results/ipapi_com.rb +45 -0
- data/lib/geocoder/results/ipdata_co.rb +40 -0
- data/lib/geocoder/results/ipgeolocation.rb +59 -0
- data/lib/geocoder/results/ipinfo_io.rb +48 -0
- data/lib/geocoder/results/ipregistry.rb +308 -0
- data/lib/geocoder/results/ipstack.rb +60 -0
- data/lib/geocoder/results/latlon.rb +71 -0
- data/lib/geocoder/results/location_iq.rb +6 -0
- data/lib/geocoder/results/mapbox.rb +57 -0
- data/lib/geocoder/results/mapquest.rb +5 -8
- data/lib/geocoder/results/maxmind.rb +0 -5
- data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
- data/lib/geocoder/results/maxmind_local.rb +0 -5
- data/lib/geocoder/results/nominatim.rb +18 -3
- data/lib/geocoder/results/opencagedata.rb +20 -2
- data/lib/geocoder/results/osmnames.rb +56 -0
- data/lib/geocoder/results/pelias.rb +58 -0
- data/lib/geocoder/results/pickpoint.rb +6 -0
- data/lib/geocoder/results/pointpin.rb +0 -4
- data/lib/geocoder/results/postcodes_io.rb +40 -0
- data/lib/geocoder/results/smarty_streets.rb +55 -19
- data/lib/geocoder/results/telize.rb +0 -5
- data/lib/geocoder/results/tencent.rb +72 -0
- data/lib/geocoder/results/test.rb +1 -1
- data/lib/geocoder/results/yandex.rb +57 -7
- data/lib/geocoder/sql.rb +9 -6
- data/lib/geocoder/stores/active_record.rb +49 -10
- data/lib/geocoder/stores/base.rb +2 -14
- data/lib/geocoder/stores/mongo_base.rb +0 -31
- data/lib/geocoder/version.rb +1 -1
- data/lib/geocoder.rb +2 -1
- data/lib/hash_recursive_merge.rb +1 -2
- data/lib/maxmind_database.rb +4 -4
- data/lib/tasks/geocoder.rake +29 -4
- metadata +56 -159
- data/.gitignore +0 -6
- data/.travis.yml +0 -31
- data/Rakefile +0 -25
- data/gemfiles/Gemfile.mongoid-2.4.x +0 -16
- data/lib/geocoder/lookups/geocoder_us.rb +0 -39
- data/lib/geocoder/lookups/okf.rb +0 -43
- data/lib/geocoder/lookups/ovi.rb +0 -62
- data/lib/geocoder/lookups/yahoo.rb +0 -88
- data/lib/geocoder/results/geocoder_us.rb +0 -39
- data/lib/geocoder/results/okf.rb +0 -106
- data/lib/geocoder/results/ovi.rb +0 -62
- data/lib/geocoder/results/yahoo.rb +0 -55
- data/lib/oauth_util.rb +0 -112
- data/test/fixtures/baidu_invalid_key +0 -1
- data/test/fixtures/baidu_ip_202_198_16_3 +0 -19
- data/test/fixtures/baidu_ip_invalid_key +0 -1
- data/test/fixtures/baidu_ip_no_results +0 -1
- data/test/fixtures/baidu_no_results +0 -1
- data/test/fixtures/baidu_reverse +0 -1
- data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
- data/test/fixtures/bing_invalid_key +0 -1
- data/test/fixtures/bing_madison_square_garden +0 -40
- data/test/fixtures/bing_no_results +0 -16
- data/test/fixtures/bing_reverse +0 -42
- data/test/fixtures/cloudmade_invalid_key +0 -1
- data/test/fixtures/cloudmade_madison_square_garden +0 -1
- data/test/fixtures/cloudmade_no_results +0 -1
- data/test/fixtures/esri_madison_square_garden +0 -59
- data/test/fixtures/esri_no_results +0 -8
- data/test/fixtures/esri_reverse +0 -21
- data/test/fixtures/freegeoip_74_200_247_59 +0 -12
- data/test/fixtures/freegeoip_no_results +0 -1
- data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
- data/test/fixtures/geocoder_ca_no_results +0 -1
- data/test/fixtures/geocoder_ca_reverse +0 -34
- data/test/fixtures/geocoder_us_madison_square_garden +0 -1
- data/test/fixtures/geocoder_us_no_results +0 -1
- data/test/fixtures/geocodio_1101_pennsylvania_ave +0 -1
- data/test/fixtures/geocodio_bad_api_key +0 -3
- data/test/fixtures/geocodio_invalid +0 -4
- data/test/fixtures/geocodio_no_results +0 -1
- data/test/fixtures/geocodio_over_query_limit +0 -4
- data/test/fixtures/google_garbage +0 -456
- data/test/fixtures/google_madison_square_garden +0 -57
- data/test/fixtures/google_no_city_data +0 -44
- data/test/fixtures/google_no_locality +0 -51
- data/test/fixtures/google_no_results +0 -4
- data/test/fixtures/google_over_limit +0 -4
- data/test/fixtures/google_places_details_invalid_request +0 -4
- data/test/fixtures/google_places_details_madison_square_garden +0 -120
- data/test/fixtures/google_places_details_no_results +0 -4
- data/test/fixtures/google_places_details_no_reviews +0 -60
- data/test/fixtures/google_places_details_no_types +0 -66
- data/test/fixtures/here_madison_square_garden +0 -72
- data/test/fixtures/here_no_results +0 -8
- data/test/fixtures/mapquest_error +0 -16
- data/test/fixtures/mapquest_invalid_api_key +0 -16
- data/test/fixtures/mapquest_invalid_request +0 -16
- data/test/fixtures/mapquest_madison_square_garden +0 -52
- data/test/fixtures/mapquest_no_results +0 -16
- data/test/fixtures/maxmind_24_24_24_21 +0 -1
- data/test/fixtures/maxmind_24_24_24_22 +0 -1
- data/test/fixtures/maxmind_24_24_24_23 +0 -1
- data/test/fixtures/maxmind_24_24_24_24 +0 -1
- data/test/fixtures/maxmind_74_200_247_59 +0 -1
- data/test/fixtures/maxmind_invalid_key +0 -1
- data/test/fixtures/maxmind_no_results +0 -1
- data/test/fixtures/nominatim_madison_square_garden +0 -150
- data/test/fixtures/nominatim_no_results +0 -1
- data/test/fixtures/nominatim_over_limit +0 -1
- data/test/fixtures/okf_kirstinmaki +0 -67
- data/test/fixtures/okf_no_results +0 -4
- data/test/fixtures/opencagedata_invalid_api_key +0 -25
- data/test/fixtures/opencagedata_invalid_request +0 -26
- data/test/fixtures/opencagedata_madison_square_garden +0 -73
- data/test/fixtures/opencagedata_no_results +0 -29
- data/test/fixtures/opencagedata_over_limit +0 -31
- data/test/fixtures/ovi_madison_square_garden +0 -72
- data/test/fixtures/ovi_no_results +0 -8
- data/test/fixtures/pointpin_10_10_10_10 +0 -1
- data/test/fixtures/pointpin_555_555_555_555 +0 -1
- data/test/fixtures/pointpin_80_111_555_555 +0 -1
- data/test/fixtures/pointpin_no_results +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +0 -1
- data/test/fixtures/smarty_streets_11211 +0 -1
- data/test/fixtures/smarty_streets_madison_square_garden +0 -47
- data/test/fixtures/smarty_streets_no_results +0 -1
- data/test/fixtures/telize_10_10_10_10 +0 -1
- data/test/fixtures/telize_555_555_555_555 +0 -4
- data/test/fixtures/telize_74_200_247_59 +0 -1
- data/test/fixtures/telize_no_results +0 -1
- data/test/fixtures/yahoo_error +0 -1
- data/test/fixtures/yahoo_invalid_key +0 -2
- data/test/fixtures/yahoo_madison_square_garden +0 -52
- data/test/fixtures/yahoo_no_results +0 -10
- data/test/fixtures/yahoo_over_limit +0 -2
- data/test/fixtures/yandex_canada_rue_dupuis_14 +0 -446
- data/test/fixtures/yandex_invalid_key +0 -1
- data/test/fixtures/yandex_kremlin +0 -48
- data/test/fixtures/yandex_new_york +0 -1
- data/test/fixtures/yandex_no_city_and_town +0 -112
- data/test/fixtures/yandex_no_results +0 -16
- data/test/integration/http_client_test.rb +0 -31
- data/test/mongoid_test_helper.rb +0 -43
- data/test/test_helper.rb +0 -416
- data/test/unit/active_record_test.rb +0 -16
- data/test/unit/cache_test.rb +0 -37
- data/test/unit/calculations_test.rb +0 -220
- data/test/unit/configuration_test.rb +0 -55
- data/test/unit/error_handling_test.rb +0 -56
- data/test/unit/geocoder_test.rb +0 -78
- data/test/unit/https_test.rb +0 -17
- data/test/unit/ip_address_test.rb +0 -27
- data/test/unit/lookup_test.rb +0 -153
- data/test/unit/lookups/bing_test.rb +0 -68
- data/test/unit/lookups/dstk_test.rb +0 -26
- data/test/unit/lookups/esri_test.rb +0 -48
- data/test/unit/lookups/freegeoip_test.rb +0 -27
- data/test/unit/lookups/geocoder_ca_test.rb +0 -17
- data/test/unit/lookups/geocodio_test.rb +0 -55
- data/test/unit/lookups/geoip2_test.rb +0 -27
- data/test/unit/lookups/google_places_details_test.rb +0 -122
- data/test/unit/lookups/google_premier_test.rb +0 -22
- data/test/unit/lookups/google_test.rb +0 -84
- data/test/unit/lookups/mapquest_test.rb +0 -60
- data/test/unit/lookups/maxmind_local_test.rb +0 -28
- data/test/unit/lookups/maxmind_test.rb +0 -63
- data/test/unit/lookups/nominatim_test.rb +0 -31
- data/test/unit/lookups/okf_test.rb +0 -38
- data/test/unit/lookups/opencagedata_test.rb +0 -64
- data/test/unit/lookups/pointpin_test.rb +0 -30
- data/test/unit/lookups/postcode_anywhere_uk_test.rb +0 -70
- data/test/unit/lookups/smarty_streets_test.rb +0 -71
- data/test/unit/lookups/telize_test.rb +0 -36
- data/test/unit/lookups/yahoo_test.rb +0 -35
- data/test/unit/method_aliases_test.rb +0 -26
- data/test/unit/model_test.rb +0 -38
- data/test/unit/mongoid_test.rb +0 -47
- data/test/unit/near_test.rb +0 -87
- data/test/unit/oauth_util_test.rb +0 -31
- data/test/unit/proxy_test.rb +0 -37
- data/test/unit/query_test.rb +0 -52
- data/test/unit/rake_task_test.rb +0 -21
- data/test/unit/request_test.rb +0 -35
- data/test/unit/result_test.rb +0 -72
- data/test/unit/test_mode_test.rb +0 -70
@@ -12,19 +12,23 @@ module Geocoder::Lookup
|
|
12
12
|
"http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def supported_protocols
|
16
|
+
[:https]
|
17
17
|
end
|
18
18
|
|
19
19
|
private # ---------------------------------------------------------------
|
20
20
|
|
21
|
+
def base_query_url(query)
|
22
|
+
"#{protocol}://geocode-maps.yandex.ru/1.x/?"
|
23
|
+
end
|
24
|
+
|
21
25
|
def results(query)
|
22
26
|
return [] unless doc = fetch_data(query)
|
23
27
|
if err = doc['error']
|
24
28
|
if err["status"] == 401 and err["message"] == "invalid key"
|
25
|
-
raise_error(Geocoder::InvalidApiKey) || warn
|
29
|
+
raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid API key.")
|
26
30
|
else
|
27
|
-
warn "Yandex Geocoding API error: #{err['status']} (#{err['message']})."
|
31
|
+
Geocoder.log(:warn, "Yandex Geocoding API error: #{err['status']} (#{err['message']}).")
|
28
32
|
end
|
29
33
|
return []
|
30
34
|
end
|
@@ -32,7 +36,7 @@ module Geocoder::Lookup
|
|
32
36
|
meta = doc['metaDataProperty']['GeocoderResponseMetaData']
|
33
37
|
return meta['found'].to_i > 0 ? doc['featureMember'] : []
|
34
38
|
else
|
35
|
-
warn "Yandex Geocoding API error: unexpected response format."
|
39
|
+
Geocoder.log(:warn, "Yandex Geocoding API error: unexpected response format.")
|
36
40
|
return []
|
37
41
|
end
|
38
42
|
end
|
@@ -43,12 +47,16 @@ module Geocoder::Lookup
|
|
43
47
|
else
|
44
48
|
q = query.sanitized_text
|
45
49
|
end
|
46
|
-
{
|
50
|
+
params = {
|
47
51
|
:geocode => q,
|
48
52
|
:format => "json",
|
49
|
-
:
|
50
|
-
:
|
51
|
-
}
|
53
|
+
:lang => "#{query.language || configuration.language}", # supports ru, uk, be, default -> ru
|
54
|
+
:apikey => configuration.api_key
|
55
|
+
}
|
56
|
+
unless (bounds = query.options[:bounds]).nil?
|
57
|
+
params[:bbox] = bounds.map{ |point| "%f,%f" % point }.join('~')
|
58
|
+
end
|
59
|
+
params.merge(super)
|
52
60
|
end
|
53
61
|
end
|
54
62
|
end
|
@@ -18,7 +18,8 @@ module Geocoder
|
|
18
18
|
:units => options[:units],
|
19
19
|
:method => options[:method],
|
20
20
|
:lookup => options[:lookup],
|
21
|
-
:language => options[:language]
|
21
|
+
:language => options[:language],
|
22
|
+
:params => options[:params]
|
22
23
|
)
|
23
24
|
end
|
24
25
|
|
@@ -35,7 +36,8 @@ module Geocoder
|
|
35
36
|
:units => options[:units],
|
36
37
|
:method => options[:method],
|
37
38
|
:lookup => options[:lookup],
|
38
|
-
:language => options[:language]
|
39
|
+
:language => options[:language],
|
40
|
+
:params => options[:params]
|
39
41
|
)
|
40
42
|
end
|
41
43
|
|
@@ -47,4 +49,3 @@ module Geocoder
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
50
|
-
|
data/lib/geocoder/query.rb
CHANGED
@@ -32,7 +32,7 @@ module Geocoder
|
|
32
32
|
# appropriate to the Query text.
|
33
33
|
#
|
34
34
|
def lookup
|
35
|
-
if ip_address?
|
35
|
+
if !options[:street_address] and (options[:ip_address] or ip_address?)
|
36
36
|
name = options[:ip_lookup] || Configuration.ip_lookup || Geocoder::Lookup.ip_services.first
|
37
37
|
else
|
38
38
|
name = options[:lookup] || Configuration.lookup || Geocoder::Lookup.street_services.first
|
@@ -66,6 +66,13 @@ module Geocoder
|
|
66
66
|
IpAddress.new(text).valid? rescue false
|
67
67
|
end
|
68
68
|
|
69
|
+
##
|
70
|
+
# Is the Query text a loopback or private IP address?
|
71
|
+
#
|
72
|
+
def internal_ip_address?
|
73
|
+
ip_address? && IpAddress.new(text).internal?
|
74
|
+
end
|
75
|
+
|
69
76
|
##
|
70
77
|
# Is the Query text a loopback IP address?
|
71
78
|
#
|
@@ -73,6 +80,13 @@ module Geocoder
|
|
73
80
|
ip_address? && IpAddress.new(text).loopback?
|
74
81
|
end
|
75
82
|
|
83
|
+
##
|
84
|
+
# Is the Query text a private IP address?
|
85
|
+
#
|
86
|
+
def private_ip_address?
|
87
|
+
ip_address? && IpAddress.new(text).private?
|
88
|
+
end
|
89
|
+
|
76
90
|
##
|
77
91
|
# Does the given string look like latitude/longitude coordinates?
|
78
92
|
#
|
data/lib/geocoder/railtie.rb
CHANGED
@@ -4,7 +4,7 @@ module Geocoder
|
|
4
4
|
if defined? Rails::Railtie
|
5
5
|
require 'rails'
|
6
6
|
class Railtie < Rails::Railtie
|
7
|
-
initializer 'geocoder.insert_into_active_record' do
|
7
|
+
initializer 'geocoder.insert_into_active_record', before: :load_config_initializers do
|
8
8
|
ActiveSupport.on_load :active_record do
|
9
9
|
Geocoder::Railtie.insert
|
10
10
|
end
|
data/lib/geocoder/request.rb
CHANGED
@@ -1,25 +1,114 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
1
3
|
module Geocoder
|
2
4
|
module Request
|
3
5
|
|
6
|
+
# The location() method is vulnerable to trivial IP spoofing.
|
7
|
+
# Don't use it in authorization/authentication code, or any
|
8
|
+
# other security-sensitive application. Use safe_location
|
9
|
+
# instead.
|
4
10
|
def location
|
5
|
-
@location ||=
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
@location ||= Geocoder.search(geocoder_spoofable_ip, ip_address: true).first
|
12
|
+
end
|
13
|
+
|
14
|
+
# This safe_location() protects you from trivial IP spoofing.
|
15
|
+
# For requests that go through a proxy that you haven't
|
16
|
+
# whitelisted as trusted in your Rack config, you will get the
|
17
|
+
# location for the IP of the last untrusted proxy in the chain,
|
18
|
+
# not the original client IP. You WILL NOT get the location
|
19
|
+
# corresponding to the original client IP for any request sent
|
20
|
+
# through a non-whitelisted proxy.
|
21
|
+
def safe_location
|
22
|
+
@safe_location ||= Geocoder.search(ip, ip_address: true).first
|
23
|
+
end
|
24
|
+
|
25
|
+
# There's a whole zoo of nonstandard headers added by various
|
26
|
+
# proxy softwares to indicate original client IP.
|
27
|
+
# ANY of these can be trivially spoofed!
|
28
|
+
# (except REMOTE_ADDR, which should by set by your server,
|
29
|
+
# and is included at the end as a fallback.
|
30
|
+
# Order does matter: we're following the convention established in
|
31
|
+
# ActionDispatch::RemoteIp::GetIp::calculate_ip()
|
32
|
+
# https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/remote_ip.rb
|
33
|
+
# where the forwarded_for headers, possibly containing lists,
|
34
|
+
# are arbitrarily preferred over headers expected to contain a
|
35
|
+
# single address.
|
36
|
+
GEOCODER_CANDIDATE_HEADERS = ['HTTP_X_FORWARDED_FOR',
|
37
|
+
'HTTP_X_FORWARDED',
|
38
|
+
'HTTP_FORWARDED_FOR',
|
39
|
+
'HTTP_FORWARDED',
|
40
|
+
'HTTP_X_CLIENT_IP',
|
41
|
+
'HTTP_CLIENT_IP',
|
42
|
+
'HTTP_X_REAL_IP',
|
43
|
+
'HTTP_X_CLUSTER_CLIENT_IP',
|
44
|
+
'REMOTE_ADDR']
|
45
|
+
|
46
|
+
def geocoder_spoofable_ip
|
47
|
+
|
48
|
+
# We could use a more sophisticated IP-guessing algorithm here,
|
49
|
+
# in which we'd try to resolve the use of different headers by
|
50
|
+
# different proxies. The idea is that by comparing IPs repeated
|
51
|
+
# in different headers, you can sometimes decide which header
|
52
|
+
# was used by a proxy further along in the chain, and thus
|
53
|
+
# prefer the headers used earlier. However, the gains might not
|
54
|
+
# be worth the performance tradeoff, since this method is likely
|
55
|
+
# to be called on every request in a lot of applications.
|
56
|
+
GEOCODER_CANDIDATE_HEADERS.each do |header|
|
57
|
+
if @env.has_key? header
|
58
|
+
addrs = geocoder_split_ip_addresses(@env[header])
|
59
|
+
addrs = geocoder_remove_port_from_addresses(addrs)
|
60
|
+
addrs = geocoder_reject_non_ipv4_addresses(addrs)
|
61
|
+
addrs = geocoder_reject_trusted_ip_addresses(addrs)
|
62
|
+
return addrs.first if addrs.any?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@env['REMOTE_ADDR']
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def geocoder_split_ip_addresses(ip_addresses)
|
72
|
+
ip_addresses ? ip_addresses.strip.split(/[,\s]+/) : []
|
73
|
+
end
|
74
|
+
|
75
|
+
# use Rack's trusted_proxy?() method to filter out IPs that have
|
76
|
+
# been configured as trusted; includes private ranges by
|
77
|
+
# default. (we don't want every lookup to return the location
|
78
|
+
# of our own proxy/load balancer)
|
79
|
+
def geocoder_reject_trusted_ip_addresses(ip_addresses)
|
80
|
+
ip_addresses.reject { |ip| trusted_proxy?(ip) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def geocoder_remove_port_from_addresses(ip_addresses)
|
84
|
+
ip_addresses.map do |ip|
|
85
|
+
# IPv4
|
86
|
+
if ip.count('.') > 0
|
87
|
+
ip.split(':').first
|
88
|
+
# IPv6 bracket notation
|
89
|
+
elsif match = ip.match(/\[(\S+)\]/)
|
90
|
+
match.captures.first
|
91
|
+
# IPv6 bare notation
|
13
92
|
else
|
14
|
-
|
93
|
+
ip
|
15
94
|
end
|
16
|
-
Geocoder.search(real_ip).first
|
17
95
|
end
|
18
|
-
|
96
|
+
end
|
97
|
+
|
98
|
+
def geocoder_reject_non_ipv4_addresses(ip_addresses)
|
99
|
+
ips = []
|
100
|
+
for ip in ip_addresses
|
101
|
+
begin
|
102
|
+
valid_ip = IPAddr.new(ip)
|
103
|
+
rescue
|
104
|
+
valid_ip = false
|
105
|
+
end
|
106
|
+
ips << valid_ip.to_s if valid_ip
|
107
|
+
end
|
108
|
+
return ips.any? ? ips : ip_addresses
|
19
109
|
end
|
20
110
|
end
|
21
111
|
end
|
22
112
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
113
|
+
ActionDispatch::Request.__send__(:include, Geocoder::Request) if defined?(ActionDispatch::Request)
|
114
|
+
Rack::Request.__send__(:include, Geocoder::Request) if defined?(Rack::Request)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class Amap < Base
|
5
|
+
|
6
|
+
def coordinates
|
7
|
+
location = @data['location'] || @data['roadinters'].try(:first).try(:[], 'location') \
|
8
|
+
|| address_components.try(:[], 'streetNumber').try(:[], 'location')
|
9
|
+
location.to_s.split(",").reverse.map(&:to_f)
|
10
|
+
end
|
11
|
+
|
12
|
+
def address
|
13
|
+
formatted_address
|
14
|
+
end
|
15
|
+
|
16
|
+
def state
|
17
|
+
province
|
18
|
+
end
|
19
|
+
|
20
|
+
def province
|
21
|
+
address_components['province']
|
22
|
+
end
|
23
|
+
|
24
|
+
def city
|
25
|
+
address_components['city'] == [] ? province : address_components["city"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def district
|
29
|
+
address_components['district']
|
30
|
+
end
|
31
|
+
|
32
|
+
def street
|
33
|
+
if address_components["neighborhood"]["name"] != []
|
34
|
+
return address_components["neighborhood"]["name"]
|
35
|
+
elsif address_components['township'] != []
|
36
|
+
return address_components["township"]
|
37
|
+
else
|
38
|
+
return @data['street'] || address_components['streetNumber'].try(:[], 'street')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def street_number
|
43
|
+
@data['number'] || address_components['streetNumber'].try(:[], 'number')
|
44
|
+
end
|
45
|
+
|
46
|
+
def formatted_address
|
47
|
+
@data['formatted_address']
|
48
|
+
end
|
49
|
+
|
50
|
+
def address_components
|
51
|
+
@data['addressComponent'] || @data
|
52
|
+
end
|
53
|
+
|
54
|
+
def state_code
|
55
|
+
""
|
56
|
+
end
|
57
|
+
|
58
|
+
def postal_code
|
59
|
+
""
|
60
|
+
end
|
61
|
+
|
62
|
+
def country
|
63
|
+
"China"
|
64
|
+
end
|
65
|
+
|
66
|
+
def country_code
|
67
|
+
"CN"
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Get address components of a given type. Valid types are defined in
|
72
|
+
# Baidu's Geocoding API documentation and include (among others):
|
73
|
+
#
|
74
|
+
# :business
|
75
|
+
# :cityCode
|
76
|
+
#
|
77
|
+
def self.response_attributes
|
78
|
+
%w[roads pois roadinters]
|
79
|
+
end
|
80
|
+
|
81
|
+
response_attributes.each do |a|
|
82
|
+
define_method a do
|
83
|
+
@data[a]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -7,38 +7,34 @@ module Geocoder::Result
|
|
7
7
|
['lat', 'lng'].map{ |i| @data['location'][i] }
|
8
8
|
end
|
9
9
|
|
10
|
-
def address
|
11
|
-
@data['formatted_address']
|
12
|
-
end
|
13
|
-
|
14
|
-
def state
|
15
|
-
province
|
16
|
-
end
|
17
|
-
|
18
10
|
def province
|
19
|
-
@data['addressComponent']['province']
|
11
|
+
@data['addressComponent'] and @data['addressComponent']['province'] or ""
|
20
12
|
end
|
21
13
|
|
14
|
+
alias_method :state, :province
|
15
|
+
|
22
16
|
def city
|
23
|
-
@data['addressComponent']['city']
|
17
|
+
@data['addressComponent'] and @data['addressComponent']['city'] or ""
|
24
18
|
end
|
25
19
|
|
26
20
|
def district
|
27
|
-
@data['addressComponent']['district']
|
21
|
+
@data['addressComponent'] and @data['addressComponent']['district'] or ""
|
28
22
|
end
|
29
23
|
|
30
24
|
def street
|
31
|
-
@data['addressComponent']['street']
|
25
|
+
@data['addressComponent'] and @data['addressComponent']['street'] or ""
|
32
26
|
end
|
33
27
|
|
34
28
|
def street_number
|
35
|
-
@data['addressComponent']['street_number']
|
29
|
+
@data['addressComponent'] and @data['addressComponent']['street_number']
|
36
30
|
end
|
37
31
|
|
38
32
|
def formatted_address
|
39
|
-
@data['formatted_address']
|
33
|
+
@data['formatted_address'] or ""
|
40
34
|
end
|
41
35
|
|
36
|
+
alias_method :address, :formatted_address
|
37
|
+
|
42
38
|
def address_components
|
43
39
|
@data['addressComponent']
|
44
40
|
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'geocoder/results/base'
|
3
|
+
|
4
|
+
module Geocoder::Result
|
5
|
+
class BanDataGouvFr < Base
|
6
|
+
|
7
|
+
#### BASE METHODS ####
|
8
|
+
|
9
|
+
def self.response_attributes
|
10
|
+
%w[limit attribution version licence type features center]
|
11
|
+
end
|
12
|
+
|
13
|
+
response_attributes.each do |a|
|
14
|
+
unless method_defined?(a)
|
15
|
+
define_method a do
|
16
|
+
@data[a]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#### BEST RESULT ####
|
22
|
+
|
23
|
+
def result
|
24
|
+
features[0] if features.any?
|
25
|
+
end
|
26
|
+
|
27
|
+
#### GEOMETRY ####
|
28
|
+
|
29
|
+
def geometry
|
30
|
+
result['geometry'] if result
|
31
|
+
end
|
32
|
+
|
33
|
+
def precision
|
34
|
+
geometry['type'] if geometry
|
35
|
+
end
|
36
|
+
|
37
|
+
def coordinates
|
38
|
+
coords = geometry["coordinates"]
|
39
|
+
return [coords[1].to_f, coords[0].to_f]
|
40
|
+
end
|
41
|
+
|
42
|
+
#### PROPERTIES ####
|
43
|
+
|
44
|
+
# List of raw attrbutes returned by BAN data gouv fr API:
|
45
|
+
#
|
46
|
+
# :id => [string] UUID of the result, said to be not stable
|
47
|
+
# atm, based on IGN reference (Institut national de
|
48
|
+
# l'information géographique et forestière)
|
49
|
+
#
|
50
|
+
# :type => [string] result type (housenumber, street, city,
|
51
|
+
# town, village, locality)
|
52
|
+
#
|
53
|
+
# :score => [float] value between 0 and 1 giving result's
|
54
|
+
# relevancy
|
55
|
+
#
|
56
|
+
# :housenumber => [string] street number and extra information
|
57
|
+
# (bis, ter, A, B)
|
58
|
+
#
|
59
|
+
# :street => [string] street name
|
60
|
+
#
|
61
|
+
# :name => [string] housenumber and street name
|
62
|
+
#
|
63
|
+
# :postcode => [string] city post code (used for mails by La Poste,
|
64
|
+
# beware many cities got severeal postcodes)
|
65
|
+
#
|
66
|
+
# :citycode => [string] city code (INSEE reference,
|
67
|
+
# consider it as a french institutional UUID)
|
68
|
+
#
|
69
|
+
# :city => [string] city name
|
70
|
+
#
|
71
|
+
# :context => [string] department code, department name and
|
72
|
+
# region code
|
73
|
+
#
|
74
|
+
# :label => [string] full address without state, country name
|
75
|
+
# and country code
|
76
|
+
#
|
77
|
+
# CITIES ONLY PROPERTIES
|
78
|
+
#
|
79
|
+
# :adm_weight => [string] administrative weight (importance) of
|
80
|
+
# the city
|
81
|
+
#
|
82
|
+
# :population => [float] number of inhabitants with a 1000 factor
|
83
|
+
#
|
84
|
+
# For up to date doc (in french only) : https://adresse.data.gouv.fr/api/
|
85
|
+
#
|
86
|
+
def properties
|
87
|
+
result['properties'] if result
|
88
|
+
end
|
89
|
+
|
90
|
+
# List of usable Geocoder results' methods
|
91
|
+
#
|
92
|
+
# score => [float] result relevance 0 to 1
|
93
|
+
#
|
94
|
+
# location_id => [string] location's IGN UUID
|
95
|
+
#
|
96
|
+
# result_type => [string] housenumber / street / city
|
97
|
+
# / town / village / locality
|
98
|
+
#
|
99
|
+
# international_address => [string] full address with country code
|
100
|
+
#
|
101
|
+
# national_address => [string] full address with country code
|
102
|
+
#
|
103
|
+
# street_address => [string] housenumber + extra inf
|
104
|
+
# + street name
|
105
|
+
#
|
106
|
+
# street_number => [string] housenumber + extra inf
|
107
|
+
# (bis, ter, etc)
|
108
|
+
#
|
109
|
+
# street_name => [string] street's name
|
110
|
+
#
|
111
|
+
# city_name => [string] city's name
|
112
|
+
#
|
113
|
+
# city_code => [string] city's INSEE UUID
|
114
|
+
#
|
115
|
+
# postal_code => [string] city's postal code (used for mails)
|
116
|
+
#
|
117
|
+
# context => [string] city's department code, department
|
118
|
+
# name and region name
|
119
|
+
#
|
120
|
+
# demartment_name => [string] city's department name
|
121
|
+
#
|
122
|
+
# department_code => [string] city's department INSEE UUID
|
123
|
+
#
|
124
|
+
# region_name => [string] city's region name
|
125
|
+
#
|
126
|
+
# population => [string] city's inhabitants count
|
127
|
+
#
|
128
|
+
# administrative_weight => [integer] city's importance on a scale
|
129
|
+
# from 6 (capital city) to 1 (regular village)
|
130
|
+
#
|
131
|
+
def score
|
132
|
+
properties['score']
|
133
|
+
end
|
134
|
+
|
135
|
+
def location_id
|
136
|
+
properties['id']
|
137
|
+
end
|
138
|
+
|
139
|
+
# Types
|
140
|
+
#
|
141
|
+
# housenumber
|
142
|
+
# street
|
143
|
+
# city
|
144
|
+
# town
|
145
|
+
# village
|
146
|
+
# locality
|
147
|
+
#
|
148
|
+
def result_type
|
149
|
+
properties['type']
|
150
|
+
end
|
151
|
+
|
152
|
+
def international_address
|
153
|
+
"#{national_address}, #{country}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def national_address
|
157
|
+
properties['label']
|
158
|
+
end
|
159
|
+
|
160
|
+
def street_address
|
161
|
+
properties['name']
|
162
|
+
end
|
163
|
+
|
164
|
+
def street_number
|
165
|
+
properties['housenumber']
|
166
|
+
end
|
167
|
+
|
168
|
+
def street_name
|
169
|
+
properties['street']
|
170
|
+
end
|
171
|
+
|
172
|
+
def city_name
|
173
|
+
properties['city']
|
174
|
+
end
|
175
|
+
|
176
|
+
def city_code
|
177
|
+
properties['citycode']
|
178
|
+
end
|
179
|
+
|
180
|
+
def postal_code
|
181
|
+
properties['postcode']
|
182
|
+
end
|
183
|
+
|
184
|
+
def context
|
185
|
+
properties['context'].split(/,/).map(&:strip)
|
186
|
+
end
|
187
|
+
|
188
|
+
def department_code
|
189
|
+
context[0] if context.length > 0
|
190
|
+
end
|
191
|
+
|
192
|
+
# Monkey logic to handle fact Paris is both a city and a department
|
193
|
+
# in Île-de-France region
|
194
|
+
def department_name
|
195
|
+
if context.length > 1
|
196
|
+
if context[1] == "Île-de-France"
|
197
|
+
"Paris"
|
198
|
+
else
|
199
|
+
context[1]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def region_name
|
205
|
+
if context.length == 2 && context[1] == "Île-de-France"
|
206
|
+
context[1]
|
207
|
+
elsif context.length > 2
|
208
|
+
context[2]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def country
|
213
|
+
"France"
|
214
|
+
end
|
215
|
+
|
216
|
+
# Country code types
|
217
|
+
# FR : France
|
218
|
+
# GF : Guyane Française
|
219
|
+
# RE : Réunion
|
220
|
+
# NC : Nouvelle-Calédonie
|
221
|
+
# GP : Guadeloupe
|
222
|
+
# MQ : Martinique
|
223
|
+
# MU : Maurice
|
224
|
+
# PF : Polynésie française
|
225
|
+
#
|
226
|
+
# Will need refacto to handle different country codes, but BAN API
|
227
|
+
# is currently mainly designed for geocode FR country code addresses
|
228
|
+
def country_code
|
229
|
+
"FR"
|
230
|
+
end
|
231
|
+
|
232
|
+
#### ALIAS METHODS ####
|
233
|
+
|
234
|
+
alias_method :address, :international_address
|
235
|
+
alias_method :street, :street_name
|
236
|
+
alias_method :city, :city_name
|
237
|
+
alias_method :state, :region_name
|
238
|
+
alias_method :state_code, :state
|
239
|
+
|
240
|
+
#### CITIES' METHODS ####
|
241
|
+
|
242
|
+
def population
|
243
|
+
(properties['population'].to_f * 1000).to_i if city?(result_type)
|
244
|
+
end
|
245
|
+
|
246
|
+
def administrative_weight
|
247
|
+
properties['adm_weight'].to_i if city?(result_type)
|
248
|
+
end
|
249
|
+
|
250
|
+
private
|
251
|
+
|
252
|
+
def city?(result_type)
|
253
|
+
%w(village town city).include?(result_type)
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|
@@ -20,8 +20,20 @@ module Geocoder
|
|
20
20
|
##
|
21
21
|
# A string in the given format.
|
22
22
|
#
|
23
|
+
# This default implementation dumbly follows the United States address
|
24
|
+
# format and will return incorrect results for most countries. Some APIs
|
25
|
+
# return properly formatted addresses and those should be funneled
|
26
|
+
# through this method.
|
27
|
+
#
|
23
28
|
def address(format = :full)
|
24
|
-
|
29
|
+
if state_code.to_s != ""
|
30
|
+
s = ", #{state_code}"
|
31
|
+
elsif state.to_s != ""
|
32
|
+
s = ", #{state}"
|
33
|
+
else
|
34
|
+
s = ""
|
35
|
+
end
|
36
|
+
"#{city}#{s} #{postal_code}, #{country}".sub(/^[ ,]*/, '')
|
25
37
|
end
|
26
38
|
|
27
39
|
##
|