tor_extend 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/Change.log +12 -0
  2. data/ReadME.txt +190 -0
  3. data/doc/ReadME_txt.html +301 -0
  4. data/doc/Tor.html +140 -0
  5. data/doc/Tor/Bridge.html +145 -0
  6. data/doc/Tor/CachedDesc.html +472 -0
  7. data/doc/Tor/Constants.html +185 -0
  8. data/doc/Tor/Router.html +146 -0
  9. data/doc/Tor/StatsObj.html +1209 -0
  10. data/doc/Tor/TController.html +1111 -0
  11. data/doc/created.rid +7 -0
  12. data/doc/images/add.png +0 -0
  13. data/doc/images/brick.png +0 -0
  14. data/doc/images/brick_link.png +0 -0
  15. data/doc/images/bug.png +0 -0
  16. data/doc/images/bullet_black.png +0 -0
  17. data/doc/images/bullet_toggle_minus.png +0 -0
  18. data/doc/images/bullet_toggle_plus.png +0 -0
  19. data/doc/images/date.png +0 -0
  20. data/doc/images/delete.png +0 -0
  21. data/doc/images/find.png +0 -0
  22. data/doc/images/loadingAnimation.gif +0 -0
  23. data/doc/images/macFFBgHack.png +0 -0
  24. data/doc/images/package.png +0 -0
  25. data/doc/images/page_green.png +0 -0
  26. data/doc/images/page_white_text.png +0 -0
  27. data/doc/images/page_white_width.png +0 -0
  28. data/doc/images/plugin.png +0 -0
  29. data/doc/images/ruby.png +0 -0
  30. data/doc/images/tag_blue.png +0 -0
  31. data/doc/images/tag_green.png +0 -0
  32. data/doc/images/transparent.png +0 -0
  33. data/doc/images/wrench.png +0 -0
  34. data/doc/images/wrench_orange.png +0 -0
  35. data/doc/images/zoom.png +0 -0
  36. data/doc/index.html +90 -0
  37. data/doc/js/darkfish.js +153 -0
  38. data/doc/js/jquery.js +18 -0
  39. data/doc/js/navigation.js +142 -0
  40. data/doc/js/search.js +94 -0
  41. data/doc/js/search_index.js +1 -0
  42. data/doc/js/searcher.js +228 -0
  43. data/doc/lib/constants_rb.html +96 -0
  44. data/doc/lib/httpmod_rb.html +95 -0
  45. data/doc/lib/tcontroller_rb.html +93 -0
  46. data/doc/lib/tor_extend_rb.html +97 -0
  47. data/doc/lib/tstats_rb.html +93 -0
  48. data/doc/rdoc.css +543 -0
  49. data/doc/table_of_contents.html +159 -0
  50. data/lib/constants.rb +106 -0
  51. data/lib/httpmod.rb +89 -0
  52. data/lib/tcontroller.rb +475 -0
  53. data/lib/tor_extend.rb +189 -0
  54. data/lib/tstats.rb +514 -0
  55. data/tor_extend.gemspec +26 -0
  56. metadata +138 -0
@@ -0,0 +1,189 @@
1
+ # tor_extend library
2
+ # Author: Oluwaseun Remi-Omosowon (mailto:remi-omosowon@et.esiea-ouest.fr)
3
+ # Copyright: ...2011
4
+
5
+
6
+ # Tor includes the TController class, which inherits the methods from Bendiken's page[http://cypherpunk.rubyforge.org/tor/] Tor::Controller class and extends it with more methods.
7
+ # You are responsible for how you use the code. See the Unlicence in Bendiken's tor-ruby gem.
8
+ #
9
+ module Tor
10
+ require 'tor'
11
+ require 'active_record'
12
+ require 'builder'
13
+ require 'geoip'
14
+ require 'net/https'
15
+
16
+ # Tor::Constants module is loaded from constants.rb and other classes from seperate files
17
+ autoload :Constants, 'constants'
18
+ require 'tcontroller'
19
+ require 'tstats'
20
+ require 'httpmod'
21
+
22
+ # Tor::Router is a class for the active record database holding the ip-addresses, platform, fingerprint, country, latitude,longitude.
23
+ #
24
+ # <b>Transforming IP address to fingerprint</b>
25
+ # Tor::Router.where(:ipaddr=>"ipaddr")[0].fingerprint
26
+ #
27
+ class Router < ActiveRecord::Base
28
+ end
29
+
30
+ # Tor::Bridge is a class for the active record database holding the ip-addresses and port for the bridges discovered using the Tor::TController.getbridges.
31
+ #
32
+ # <b>Show all Bridges in the database</b>
33
+ # Tor::Bridge.all
34
+ #
35
+ class Bridge < ActiveRecord::Base
36
+ end
37
+
38
+ # Tor::CachedDesc is a class used to read cached descriptors into a database. The ip address, fingerprint, platform, country, latitude and longitude.
39
+ #
40
+ # @example Create database and read cached desciptor into it
41
+ # cached_descriptor = Tor::CachedDesc.new
42
+ # Tor::CachedDesc.dbconnect
43
+ # Tor::CachedDesc.dbconnect( { :adapter => "sqlite3",:database => "db.sqlite3"} )
44
+ # Tor::CachedDesc.readall("cached_descriptor_filename")
45
+ # Tor::CachedDesc.ors
46
+ # Tor::CachedDesc.ors.all
47
+ #
48
+ class CachedDesc
49
+
50
+
51
+ # This initialises the stat attribute of the CachedDesc class that can be used to get data from Tor::Router
52
+ #
53
+ def initialize(geoip_path)
54
+ @stat = StatsObj.new
55
+ # Tor::CachedDesc#geoipdb is an instance of GeoIP with the active database
56
+ @geoipdb = GeoIP.new(geoip_path[0])
57
+ # Tor::CachedDesc#geoipdb2 acts as a backup if records are not present in Tor::CachedDesc#geoipdb
58
+ @geoipdb2 = GeoIP.new(geoip_path[1])
59
+ end
60
+
61
+ # This initialises the stat attribute of the CachedDesc class that can be used to get data from Tor::Router
62
+ # It returns a Tor::StatsObj
63
+ #
64
+ def stat
65
+ @stat
66
+ end
67
+
68
+ # Tor::dbconnect() method connects using the optional database config passed as argument. It creates an sqlite3 file by default called db.sqlite3, and a table called routers.
69
+ # A table called routers is created in an existing database if it does not already exist.
70
+ #
71
+ # <b>Connecting to a database</b>
72
+ # Tor::CachedDesc.dbconnect
73
+ # Tor::CachedDesc.dbconnect( {:adapter => "sqlite3",:database => "db_name_here"} )
74
+ #
75
+ def dbconnect(*dbconfig)
76
+ dbconfig = [{:adapter => "sqlite3",:database => "db.sqlite3"}] if dbconfig.empty?
77
+ ActiveRecord::Base.establish_connection(dbconfig[0])
78
+ if !ActiveRecord::Base.connection.table_exists?('routers')
79
+ ActiveRecord::Schema.define do
80
+ create_table :routers do |t|
81
+ t.string :ipaddr
82
+ t.text :platform
83
+ t.string :fingerprint
84
+ t.string :city
85
+ t.string :country
86
+ t.string :country_code
87
+ t.string :continent
88
+ t.decimal :lat
89
+ t.decimal :lng
90
+ t.datetime :published_at
91
+ t.timestamps
92
+ end
93
+ create_table :bridges do |t|
94
+ t.string :ipaddr
95
+ t.integer :port
96
+ t.decimal :lat
97
+ t.decimal :lng
98
+ t.timestamps
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ # Returns the Router database class. Allows interation with the database as an instance of Active::Base if you know what you're doing.
105
+ #
106
+ # Display on ORs in the database.
107
+ # Cacheddec.or.all
108
+ #
109
+ def ors
110
+ Router
111
+ end
112
+
113
+
114
+ # This returns the Geoip record from one of the database files used in Tor::CachedDesc.
115
+ #
116
+ def get_geoiprecord(ipaddr)
117
+ or_geoip=@geoipdb.city(ipaddr)
118
+ or_geoip=@geoipdb2.city(ipaddr) if or_geoip==nil
119
+ or_geoip
120
+ end
121
+
122
+
123
+ # Read a file and put all the ralated information into the Tor::Router database.
124
+ #
125
+ def readall(filename)
126
+ cacheddesc = File.new(filename,'r:ISO-8859-1')
127
+ loopbreaker=false
128
+
129
+ until loopbreaker==true
130
+ fileline = cacheddesc.gets
131
+ fileline.chomp! if fileline != nil
132
+ case fileline
133
+ when /^published /
134
+ time_published = Time.parse fileline.sub("published ",'') # downloaded_at
135
+ when /^router /
136
+ or_ipaddr = fileline.scan(/\d+\.\d+\.\d+.\d+/)[0]
137
+ when /^platform /
138
+ case fileline
139
+ when /Windows/i
140
+ osplatform ="WINDOWS"
141
+ when /SunOS/i
142
+ osplatform ="SUN"
143
+ when /Linux/i,/Ubuntu/i
144
+ osplatform ="LINUX"
145
+ when /Unix/i, /BSD/i,/DragonFly/i,/Darwin/i
146
+ osplatform ="UNIX"
147
+ else
148
+ osplatform ="OTHER"
149
+ end
150
+
151
+ when /^opt fingerprint /
152
+ or_fingerprint=fileline.split("opt fingerprint ")[1].split.join # the fingerprint
153
+ # puts or_ipaddr
154
+ or_geoip=@geoipdb.city(or_ipaddr)
155
+ or_geoip=@geoipdb2.city(or_ipaddr) if or_geoip==nil # noticed that the august database returns nil for an address like 208.64.240.182, and smaller in size than July
156
+ if or_geoip.nil?
157
+ puts "#{or_ipaddr} not found in both geoip databases, try get an updated one, or older one."
158
+ else
159
+ or_city = or_geoip.city_name
160
+ or_country = or_geoip.country_name
161
+ orcountry_code = or_geoip.country_code2
162
+ orcontinent = or_geoip.continent_code
163
+ lng = or_geoip.longitude.to_f
164
+ lat = or_geoip.latitude.to_f
165
+ tmpr = Router.where(:ipaddr=>or_ipaddr).first
166
+ if tmpr.nil?
167
+ Router.create(:ipaddr=>or_ipaddr, :fingerprint=>or_fingerprint, :lat=>lat, :lng=>lng, :platform=>osplatform, :city=>or_city,
168
+ :country=>or_country, :continent=>orcontinent,:country_code=>orcountry_code,
169
+ :published_at=>time_published)
170
+ elsif time_published > tmpr.published_at
171
+ tmpr.fingerprint = or_fingerprint # Update fingerprint - Make sure you read newer files last
172
+ tmpr.lat = lat
173
+ tmpr.lng = lng
174
+ tmpr.platform=osplatform
175
+ tmpr.country=or_country
176
+ tmpr.save
177
+ end
178
+ end # if orgeoip.nil?
179
+ when nil
180
+ # gets returns nil for EOF
181
+ loopbreaker=true
182
+ cacheddesc.close
183
+ end
184
+ end # end of read file until eof
185
+
186
+ end
187
+ end
188
+
189
+ end # end of module
@@ -0,0 +1,514 @@
1
+ module Tor
2
+
3
+ # This class can be used to obtain a variety of statistics or data from Tor::Router.
4
+ # The same user have multiple IP addresses on different days, but the fingerprint might not change, especially not withing a month. Use uniq stats when available.
5
+ #
6
+ class StatsObj
7
+
8
+ # This returns a list of all countries that have contributed to the OR IP addresses in Tor::Router
9
+ # It can return only the those that have contributed to a particular platform
10
+ #
11
+ # @example Get Countries the that use Unix
12
+ # Tor::StatsObj.country_list
13
+ # Tor::StatsObj.country_list("UNIX")
14
+ # Tor::StatsObj.country_list( ["UNIX", "LINUX"] )
15
+ #
16
+ def country_list(*platform)
17
+ tmpresult = (platform.empty? or platform == ["ALL"]) ? Router.all : Router.where(:platform=>platform)
18
+ tmpresult.group_by{|c| c.country_code}.keys
19
+ end
20
+
21
+ # This returns a list of all continents that have contributed to the OR IP addresses in Tor::Router
22
+ # It can return only the those that have contributed to a particular platform
23
+ #
24
+ # @example Get Countries the that use Unix
25
+ # Tor::StatsObj.continent_list
26
+ # Tor::StatsObj.continent_list("UNIX")
27
+ # Tor::StatsObj.continent_list( ["UNIX", "LINUX"] )
28
+ #
29
+ def continent_list(*platform)
30
+ tmpresult = (platform.empty? or platform == ["ALL"]) ? Router.all : Router.where(:platform=>platform)
31
+ tmpresult.group_by{|c| c.continent}.keys
32
+ end
33
+
34
+ # This returns the number of OR IP addresses from the country with the code used as input (and optionally platform parameter).
35
+ #
36
+ # @example Get number of OR IP addr from continents
37
+ # Tor::StatsObj.country_count("FR")
38
+ # Tor::StatsObj.country_count("FR","UNIX")
39
+ # Tor::StatsObj.country_count( ["FR","DE"] ,[ "UNIX", "LINUX" ] )
40
+ #
41
+ def country_count(code,*platform)
42
+ rslt = (platform.empty? or platform == ["ALL"] ) ?
43
+ Router.where(:country_code=>code) :
44
+ Router.where(:country_code=>code,:platform=>platform)
45
+ rslt.count
46
+ end
47
+
48
+ # This returns the total number of uniq identities found in the database.
49
+ #
50
+ # <b>Get total number of routers in countries<b>.
51
+ # Tor::StatsObj.country_count_uniq(["GB","FR"])
52
+ # Tor::StatsObj.country_count_uniq("FR","WINDOWS")
53
+ # Tor::StatsObj.country_count_uniq(["GB","FR",DE],["UNIX",LINUX"] )
54
+ #
55
+ def country_count_uniq(countryfilter,*platform)
56
+ get_uniqid(countryfilter,*platform).count
57
+ end
58
+
59
+
60
+ # This returns the number of OR IP addresses from the continent with the code used as input (and optionally platform parameter).
61
+ #
62
+ # @example Get number of OR IP addr from continents
63
+ # Tor::StatsObj.continent_count("EU")
64
+ # Tor::StatsObj.continent_count("NA","UNIX")
65
+ # Tor::StatsObj.continent_count( ["EU","NA","SA"] ,[ "UNIX", "LINUX" ] )
66
+ #
67
+ def continent_count(code,*platform)
68
+ rslt = (platform.empty? or platform == ["ALL"] ) ? Router.where(:continent=>code) : Router.where(:continent=>code, :platform=>platform)
69
+ rslt.count # continent code "AF","EU","AS","NA","SA","OC"
70
+ end
71
+
72
+ # This returns the number of OR IP addresses from the continent with the code used as input (and optionally platform parameter).
73
+ #
74
+ # @example Get number of OR IP addr from continents
75
+ # Tor::StatsObj.continent_count("EU")
76
+ # Tor::StatsObj.continent_count("NA","UNIX")
77
+ # Tor::StatsObj.continent_count( ["EU","NA","SA"] ,[ "UNIX", "LINUX" ] )
78
+ #
79
+ def continent_count_uniq(code,*platform)
80
+ rslt = (platform.empty? or platform == ["ALL"] ) ?
81
+ Router.where(:id=> get_uniqid(country_list, *platform), :continent=>code) :
82
+ Router.where(:id=> get_uniqid(country_list, *platform), :continent=>code, :platform=>platform)
83
+ rslt.count # continent code "AF","EU","AS","NA","SA","OC"
84
+ end
85
+
86
+
87
+ # It takes an array of country codes as input, and produces a hash with the country codes as keys and the total number of ors from the country as value.
88
+ # An optional platform can also be set.
89
+ #
90
+ # @example Get country statistics
91
+ # Tor::StatsObj.country_stat(["EU","NA","SA"]) => {"EU" => country,total, .... "SA" => country,total }
92
+ # Tor::StatsObj.country_stat(["EU","NA","SA"], "LINUX")
93
+ # Tor::StatsObj.country_stat( Tor::StatsObj.country_list )
94
+ # Tor::StatsObj.country_stat( Tor::StatsObj.country_list(platform) )
95
+ #
96
+ # Note: Results of Tor::StatsObj.country_list can be used as argument for this Tor::StatsObj.country_stat.
97
+ #
98
+ def country_stat(countrycodes,*platform)
99
+ country_count_hash={}
100
+ if countrycodes.class==String
101
+ country_count_hash[countrycodes] = country_count(countrycodes,*platform)
102
+ else
103
+ countrycodes.each{|each_country| country_count_hash[each_country] = country_count(each_country,*platform)}
104
+ end
105
+ country_count_hash
106
+ end
107
+
108
+ # This retuns an array of all OR IP addresses from the Tor::Router using a filter of countries and optional platform parameter.
109
+ #
110
+ # @example Get all OR IP addresses from France
111
+ # Tor::StatsObj.country_getip("FR")
112
+ # Tor::StatsObj.country_getip(["FR",GB"], "WINDOWS")
113
+ # Tor::StatsObj.country_getip(["FR",GB"], ["WINDOWS", "LINUX"] )
114
+ #
115
+ def country_getip(country_filter,*platform)
116
+ if platform.empty? or platform == ["ALL"]
117
+ onionr = Router.where(:country_code=>country_filter)
118
+ else
119
+ onionr=Router.where(:country_code=>country_filter,:platform=>platform )
120
+ end
121
+ onion_ipaddr=onionr.collect{|each_country| each_country.ipaddr}
122
+ end
123
+
124
+ # This retuns an array of all OR fingerprints from the Tor::Router using a filter of countries and optional platform parameter.
125
+ #
126
+ # @example Get all OR IP fingerprints from France
127
+ # Tor::StatsObj.country_getingerprint("FR")
128
+ # Tor::StatsObj.country_getingerprint(["FR",GB"], "WINDOWS")
129
+ # Tor::StatsObj.country_getingerprint(["FR",GB"], ["WINDOWS", "LINUX"] )
130
+ #
131
+ def country_getfingerprint(country_filter,*platform)
132
+ if platform.empty? or platform == ["ALL"]
133
+ onionr = Router.where(:country_code=>country_filter)
134
+ else
135
+ onionr=Router.where(:country_code=>country_filter,:platform=>platform )
136
+ end
137
+ onion_ipaddr = onionr.collect{|each_country| each_country.fingerprint}
138
+ end
139
+
140
+ # This retuns an array of all OR fingerprints from Tor::Router using a filter of continents and optional platform parameter.
141
+ #
142
+ # @example Get all OR IP fingerprints from France
143
+ # Tor::StatsObj.continent_getfingerprint("EU")
144
+ # Tor::StatsObj.continent_getfingerprint(["AF",EU"], "WINDOWS")
145
+ # Tor::StatsObj.continent_getfingerprint(["NA","SA"], ["WINDOWS", "LINUX"] )
146
+ #
147
+ def continent_getfingerprint(continent_filter,*platform)
148
+ if platform.empty? or platform == ["ALL"]
149
+ onionr = Router.where(:continent=>continent_filter,:id=>get_uniqid(countryfilter,*platform))
150
+ else
151
+ onionr=Router.where(:continent=>continent_filter,:platform=>platform ,:id=>get_uniqid(countryfilter,*platform))
152
+ end
153
+ onion_ipaddr = onionr.collect{|each_country| each_country.fingerprint}
154
+ end
155
+
156
+ # It takes an array of country codes as input, and produces a hash with the country codes as keys and the total number of unique ors from the country as value.
157
+ # An optional platform can also be set.
158
+ #
159
+ # @example Get country statistics
160
+ # Tor::StatsObj.country_stat_uniq(["FR","GB","US"]) => {"FR" => total, .... "US" => total }
161
+ # Tor::StatsObj.country_stat_uniq([DE","FR"], "LINUX")
162
+ # Tor::StatsObj.country_stat_uniq( Tor::StatsObj.country_list )
163
+ # Tor::StatsObj.country_stat_uniq( Tor::StatsObj.country_list(platform) )
164
+ #
165
+ # Note: Results of Tor::StatsObj.country_list can be used as argument for this Tor::StatsObj.country_stat_uniq.
166
+ #
167
+ def country_stat_uniq(countrycodes,*platform)
168
+ # get_uniqid can be used for this, but this that will involve more calls to Tor::Router than necessary
169
+ country_count_hash={}
170
+ if countrycodes.class==String
171
+ country_count_hash[countrycodes] = country_count_uniq(countrycodes,*platform)
172
+ else
173
+ countrycodes.each{|each_country|
174
+ country_count_hash[each_country] = country_count_uniq(each_country,*platform) }
175
+ end
176
+ country_count_hash
177
+ end
178
+
179
+ # It takes an array of continent codes as input, and produces a hash with the continent codes as keys and the total number of ors from the country as value
180
+ #
181
+ # @example Get continents statistics
182
+ # Tor::StatsObj.continent_stat(["EU","NA","SA"]) => {"EU" => total, .... "SA" => total }
183
+ # Tor::StatsObj.continent_stat(["EU","NA","SA"], "LINUX")
184
+ # Tor::StatsObj.continent_stat( Tor::StatsObj.country_list )
185
+ #
186
+ # Note: Results of Tor::StatsObj.continent_list can be used as argument for this Tor::StatsObj.continent_stat.
187
+ #
188
+ def continent_stat(allcontinents,*platform)
189
+ continent_count_hash={}
190
+ if allcontinents.class==String
191
+ continent_count_hash[allcontinents] = continent_count(allcontinents,*platform)
192
+ else
193
+ allcontinents.each{|each_continent|
194
+ continent_count_hash[each_continent] = continent_count(each_continent,*platform)
195
+ }
196
+ end
197
+ continent_count_hash
198
+ end
199
+
200
+ # It takes an array of continent codes as input, and produces a hash with the continent codes as keys and the total number of ors from the country as value
201
+ #
202
+ # @example Get continents statistics
203
+ # Tor::StatsObj.continent_stat_uniq(["EU","NA","SA"]) => {"EU" => total, .... "SA" => total }
204
+ # Tor::StatsObj.continent_stat_uniq(["EU","NA","SA"], "LINUX")
205
+ # Tor::StatsObj.continent_stat_uniq( Tor::StatsObj.country_list )
206
+ #
207
+ # Note: Results of Tor::StatsObj.continent_list can be used as argument for this Tor::StatsObj.continent_stat_uniq.
208
+ #
209
+ def continent_stat_uniq(allcontinents,*platform)
210
+ continent_count_hash={}
211
+ if allcontinents.class==String
212
+ continent_count_hash[allcontinents] = continent_count_uniq(allcontinents,*platform)
213
+ else
214
+ allcontinents.each{|each_continent|
215
+ continent_count_hash[each_continent] = continent_count_uniq(each_continent,*platform)
216
+ }
217
+ end
218
+ continent_count_hash
219
+ end
220
+
221
+ # This returns the top n-countries. An optional platform parameter can be passed to this
222
+ # and returns an array of countries and total
223
+ #
224
+ # @example Top n-countries
225
+ # Tor::StatsObj.topcountries(n) => [[country,total]....[country,total]]
226
+ # Tor::StatsObj.topcountries(n, "UNIX")
227
+ # Tor::StatsObj.topcountries(n, ["UNIX","LINUX"])
228
+ #
229
+ def topcountries(num,*platform)
230
+ countryarray = country_list(*platform)
231
+ top_countries = country_stat(countryarray,*platform).sort_by{|k,v| v}
232
+ result = (num==0) ? top_countries.reverse : top_countries.last(num).reverse
233
+ end
234
+
235
+ # This returns the top n-countries. An optional platform parameter can be passed to this
236
+ # and returns an array of countries and total
237
+ #
238
+ # @example Top n-countries
239
+ # Tor::StatsObj.topcountries_uniq(n) => [[country,total]....[country,total]]
240
+ # Tor::StatsObj.topcountries_uniq(n, "UNIX")
241
+ # Tor::StatsObj.topcountries_uniq(n, ["UNIX","LINUX"])
242
+ #
243
+ def topcountries_uniq(num,*platform)
244
+ countryarray = country_list(*platform)
245
+ top_countries = country_stat_uniq(countryarray,*platform).sort_by{|k,v| v}
246
+ result = (num==0) ? top_countries.reverse : top_countries.last(num).reverse
247
+ end
248
+
249
+ # This returns the country name from the country code.
250
+ #
251
+ # @example Get country name from country code
252
+ # Tor::StatsObj.get_countryname("FR")
253
+ #
254
+ def get_countryname(ccode)
255
+ x=Router.where(:country_code=>ccode).first
256
+ (x.nil?) ? nil : x.country
257
+ end
258
+
259
+ # This returns the [latitude,longitude] from the country code. Using the constant Tor::Constants::COUNLATLNG,
260
+ # or alternatively if Tor::COUNLATLNG has been defined in a program.
261
+ #
262
+ def get_latlng(country_code)
263
+ countrylatlng = Constants::COUNLATLNG
264
+ if (defined? COUNLATLNG)
265
+ if (COUNLATLNG.keys.include? country_code)
266
+ lat= COUNLATLNG[country_code][:lat]
267
+ lng= COUNLATLNG[country_code][:lng]
268
+ end
269
+ elsif countrylatlng.keys.include? country_code
270
+ lat=countrylatlng[country_code][:lat]
271
+ lng=countrylatlng[country_code][:lng]
272
+ else
273
+ puts "#{country_code}, #{get_countryname(country_code)} - not in the country-latitude file, using cordinates(0,0)"
274
+ lat=0.0
275
+ lng=0.0
276
+ end
277
+ [lat,lng]
278
+ end
279
+
280
+
281
+ # This returns the id of uniq identities in the database
282
+ #
283
+ # @example Get Uniq id of ORs in the UK
284
+ #
285
+ # Tor::Stats.Obj.get_uniqid("GB")
286
+ # Tor::Stats.Obj.get_uniqid("GB","WINDOWS")
287
+ # Tor::Stats.Obj.get_uniqid(["GB","FR",DE"] , ["UNIX","LINUX"])
288
+ #
289
+ def get_uniqid(countryfilter,*platform)
290
+ if platform.empty? or platform==["ALL"] or platform==["All"]
291
+ torlocations = Router.where(:country_code=>countryfilter)
292
+ else
293
+ torlocations = Router.where(:platform=>platform,:country_code=>countryfilter)
294
+ end
295
+ identitygroup = torlocations.group_by{|c| c.fingerprint}
296
+ idarray = identitygroup.keys.collect{|eachidentitykey|
297
+ #Collect just the id of the most recent location of the fingerprint
298
+ identitygroup[eachidentitykey].max{|a,b| a.published_at <=> b.published_at}.id
299
+ }
300
+ end
301
+
302
+ # This method generates a KML using the locations in Tor::Router database.
303
+ # It takes a name for the KML document as input, and an optional platform parameter.
304
+ #
305
+ # @example Generate KML file
306
+ # Tor::StatsObj.genkml("KML doc name")
307
+ # Tor::StatsObj.genkml("KML platform name", ["WINDOWS","UNIX","LINUX", "OTHER"] )
308
+ # Tor::StatsObj.genkml("KML platform name", "LINUX" )
309
+ #
310
+ def genkml(mapname,*platform)
311
+ tour_hash= (defined? WORLDTOUR) ? WORLDTOUR : Constants::WORLDTOUR
312
+ attack_tour = (defined? ATTACK_TOUR) ? ATTACK_TOUR: Constants::ATTACK_TOUR
313
+
314
+ torcountry= topcountries_uniq(0,*platform) # collect{|country,count| country}
315
+ xml = Builder::XmlMarkup.new(:indent=>2)
316
+ xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
317
+ xml.kml("xmlns" => "http://www.opengis.net/kml/2.2",
318
+ "xmlns:gx"=>"http://www.google.com/kml/ext/2.2") do
319
+ y=1
320
+
321
+
322
+ xml.Document do
323
+ xml.name mapname
324
+
325
+ # define styles to use for placemarks and tour
326
+ xml.Style("id"=>"redplaces") do
327
+ xml.IconStyle do
328
+ xml.color "ff0000ff"
329
+ end
330
+ end
331
+ xml.Style("id"=>"greenplaces") do
332
+ xml.IconStyle do
333
+ xml.color "ff00ff00"
334
+ end
335
+ end
336
+ xml.Style("id"=>"blackplaces") do
337
+ xml.IconStyle do
338
+ xml.color "ff000000"
339
+ end
340
+ end
341
+ xml.Style("id"=>"blueplaces") do
342
+ xml.IconStyle do
343
+ xml.color "0000ff00"
344
+ end
345
+ end
346
+
347
+ xml.Folder("id"=>"torbridges") do
348
+ xml.name "Tor Bridges - #{Bridge.count}"
349
+ allbridges = Bridge.all
350
+ allbridges.each{|eachbridge|
351
+ brindex = 1 + allbridges.index(eachbridge)
352
+ placeid = "bridge#{brindex }"
353
+ xml.Placemark("id"=> placeid) do
354
+ xml.name "BR#{brindex.to_s}"
355
+ xml.description "#{eachbridge.ipaddr}:#{eachbridge.port}"
356
+ xml.styleUrl "#blueplaces"
357
+ xml.Point do
358
+ xml.extrude 1
359
+ xml.coordinates "#{eachbridge.lng},#{eachbridge.lat}"
360
+ end
361
+ end
362
+ }
363
+ end
364
+
365
+ # Google earth tour
366
+ xml.gx :Tour do
367
+ xml.name "Tor World"
368
+ xml.gx :Playlist do
369
+ tour_hash.keys.each{|each_centre|
370
+ xml.gx :FlyTo do
371
+ xml.gx :duration,1.0
372
+ xml.LookAt do
373
+ country_lat,country_lng= get_latlng(each_centre)
374
+ xml.longitude country_lng
375
+ xml.latitude country_lat
376
+ xml.range 4900000
377
+ end #end LookAt
378
+ end # end FlyTo
379
+
380
+
381
+ tour_hash[each_centre].each{|eachzone|
382
+ # toggle on
383
+ xml.gx :AnimatedUpdate do
384
+ xml.gx :duration,0.0
385
+ xml.Update do
386
+ xml.targetHref
387
+ xml.Change do
388
+ xml.Placemark("targetId"=> eachzone) do
389
+ xml.gx :balloonVisibility,1
390
+ end # end Placemark
391
+ end # end Change
392
+ end # end Update
393
+ end #end AnimatedUpdate
394
+ xml.gx :Wait do
395
+ xml.gx :duration,2.0
396
+ end
397
+
398
+ # toggle off
399
+ xml.gx :AnimatedUpdate do
400
+ xml.gx :duration,0.0
401
+ xml.Update do
402
+ xml.targetHref
403
+ xml.Change do
404
+ xml.Placemark("id"=> eachzone) do
405
+ xml.gx :balloonVisibility,0
406
+ end # end placemark
407
+ end # end Change
408
+ end # end Update
409
+ end # end AnimatedUpdate
410
+ xml.gx :Wait do
411
+ xml.gx :duration,2.0
412
+ end
413
+ } # eachzone
414
+ } #each_centre
415
+ end # end of gx:Playlist
416
+ end # end of gx:Tour
417
+
418
+
419
+ # Google earth attack tour
420
+ xml.gx :Tour do
421
+ xml.name "Tor - Attack"
422
+ xml.gx :Playlist do
423
+ xml.gx :FlyTo do
424
+ xml.gx :duration,1.0
425
+ xml.LookAt do
426
+ xml.longitude attack_tour[:lng]
427
+ xml.latitude attack_tour[:lat]
428
+ xml.range 2000000
429
+ end #end LookAt
430
+ end # end FlyTo
431
+
432
+
433
+ attack_tour["red"].each{|eachzone|
434
+ # toggle on
435
+ xml.gx :AnimatedUpdate do
436
+ xml.gx :duration,0.0
437
+ xml.Update do
438
+ xml.targetHref
439
+ xml.Change do
440
+ xml.Placemark("targetId"=> eachzone) do
441
+ xml.styleUrl "#redplaces"
442
+ end # end Placemark
443
+ end # end Change
444
+ end # end Update
445
+ end #end AnimatedUpdate
446
+ } # eachzone
447
+
448
+ attack_tour["black"].each{|eachzone|
449
+ # toggle on
450
+ xml.gx :AnimatedUpdate do
451
+ xml.gx :duration,2.0
452
+ xml.Update do
453
+ xml.targetHref
454
+ xml.Change do
455
+ xml.Placemark("targetId"=> eachzone) do
456
+ xml.styleUrl "#blackplaces"
457
+ end # end Placemark
458
+ end # end Change
459
+ end # end Update
460
+ end #end AnimatedUpdate
461
+ xml.gx :Wait do
462
+ xml.gx :duration,2.0
463
+ end
464
+ } # eachzone
465
+
466
+ end # end of gx:Playlist
467
+ end # end of gx:Tour
468
+
469
+ torcountry.each { |country_code,countrytotal|
470
+ countryname = get_countryname(country_code)
471
+ xml.Folder("id"=>country_code) do
472
+ xml.name "#{countryname}-#{countrytotal}"
473
+ xml.LookAt do
474
+ country_lat,country_lng = get_latlng(country_code)
475
+ xml.longitude country_lng
476
+ xml.latitude country_lat
477
+ xml.range 4500000
478
+ end
479
+ idarray = get_uniqid(country_code,*platform)
480
+ if platform.empty? or platform==["ALL"] or platform==["All"]
481
+ torlocations = Router.where(:id=>idarray,:country_code=>country_code)
482
+ else
483
+ torlocations = Router.where(:id=>idarray,:country_code=>country_code,:platform=>platform)
484
+ end
485
+ torplaces_sorted = torlocations.group_by{|c| [ c.lat, c.lng, c.country, c.city ] }.sort_by{|a,b| b.count}.reverse
486
+ torplaces_sorted.each{|lat_lng_country_city|
487
+ # Group by fingerprint here and get the size of the hash, and get the number of elements in the hash instead of get_uniqid
488
+ # but what if user is mobile? different isps, latitude-longitude, or lives the city or country
489
+ lat, lng, country, city = lat_lng_country_city[0]
490
+ pointtotal = lat_lng_country_city[1].count
491
+ placeid = "#{country_code}#{ 1 + torplaces_sorted.index(lat_lng_country_city)}"
492
+ xml.Placemark("id"=> placeid) do
493
+ strcount = (pointtotal == 1) ? 'OR' : 'ORs'
494
+ #xml.name "#{y}"
495
+ y += 1
496
+ kmlcity= (city.empty?) ? "#{country}" : "#{city}"
497
+ xml.description "#{pointtotal} #{strcount} in #{kmlcity} of #{countrytotal}(country total)"
498
+ xml.styleUrl "#greenplaces"
499
+ xml.Point do
500
+ xml.extrude 1
501
+ xml.coordinates "#{lng},#{lat}"
502
+ end
503
+ end
504
+ }
505
+ end
506
+ }
507
+ end
508
+ end
509
+ xml.target! #Return the xml file
510
+ end # end of genkml
511
+
512
+ end # end of class StatsObj
513
+
514
+ end