thm 0.4.5 → 0.5.7
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/bin/thm-session +4 -39
- data/bin/thm-trafviz +26 -145
- data/bin/thm-useradmin +2 -3
- data/config.rb +14 -1
- data/lib/thm.rb +140 -2
- data/lib/thm/datalayerlight.rb +61 -17
- data/lib/thm/dataservices.rb +6 -0
- data/lib/thm/dataservices/external.rb +68 -0
- data/lib/thm/dataservices/geolocation/geolocation.rb +46 -19
- data/lib/thm/dataservices/safebrowsing_api.rb +54 -0
- data/lib/thm/dataservices/trafviz/trafviz.rb +164 -27
- data/lib/thm/version.rb +3 -3
- data/sql/geoipdata-monetdb.sql +4 -4
- data/sql/threatmonitor-http.sql +108 -11
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b169ed01c8ea3600372b26c6586e0a972f4c3e8
|
4
|
+
data.tar.gz: 20b7c47617ee242e15560f44b245dcfde937b3c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddedda3ae04f8f916f557e5e1080cdf2173a1aff66756f1b3d467fa495ee8f1fcf743fdffdee8833014f89466798028831e96eb326e0133705fb53544d1d21be
|
7
|
+
data.tar.gz: 3ce9517ec13223cb8573d5ef9026185b37535c63dd56ed86d3e65f013605f3571e48a76c007e272670153dfbcebb5b571c9877d0982c398056bf8d1d6c754360
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -44,6 +44,8 @@ Gem::Specification.new do |spec|
|
|
44
44
|
"lib/thm/version.rb",
|
45
45
|
"lib/thm/dataservices/geolocation/geolocation.rb",
|
46
46
|
"lib/thm/dataservices/trafviz/trafviz.rb",
|
47
|
+
"lib/thm/dataservices/external.rb",
|
48
|
+
"lib/thm/dataservices/safebrowsing_api.rb",
|
47
49
|
"js/jquery.min.js",
|
48
50
|
"js/chartkick.js",
|
49
51
|
"js/JSXTransformer.js",
|
data/bin/thm-session
CHANGED
@@ -16,6 +16,7 @@ require 'chartkick'
|
|
16
16
|
require 'sinatra/base'
|
17
17
|
require 'slim'
|
18
18
|
require 'colorize'
|
19
|
+
require 'keycounter'
|
19
20
|
|
20
21
|
require File.expand_path(File.join(
|
21
22
|
File.dirname(__FILE__),
|
@@ -39,42 +40,6 @@ class Sinatra::Base
|
|
39
40
|
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
class Geocounter
|
44
|
-
|
45
|
-
# Create / Add to instance variable
|
46
|
-
def geocount(country)
|
47
|
-
country.gsub!(" ", "_") # no spaces or case
|
48
|
-
if !instance_variable_get("@#{country}")
|
49
|
-
instance_variable_set("@#{country}", 1)
|
50
|
-
else
|
51
|
-
instance_variable_set("@#{country}", instance_variable_get("@#{country}") + 1)
|
52
|
-
end
|
53
|
-
puts "Country: #{country} Value: "+instance_variable_get("@#{country}").to_s
|
54
|
-
end
|
55
|
-
|
56
|
-
# Read a single country
|
57
|
-
def geocount_reader(country)
|
58
|
-
country.gsub!(" ", "_") # no spaces or case
|
59
|
-
valnum = instance_variable_get("@#{country}")
|
60
|
-
return valnum
|
61
|
-
end
|
62
|
-
|
63
|
-
# Compile in array with the totals of all instance variables
|
64
|
-
def geocount_compile
|
65
|
-
countrycounts = Array.new
|
66
|
-
# You can't really inherit this class as the other class may also contain instance variables
|
67
|
-
# its not really an exact logic this class only works alone.
|
68
|
-
instance_variables.each {|n|
|
69
|
-
t = n.to_s.gsub("@", "")
|
70
|
-
countrycounts << ["#{t}", instance_variable_get("#{n}")]
|
71
|
-
}
|
72
|
-
return countrycounts
|
73
|
-
countrycounts
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
43
|
module ThmUI extend self
|
79
44
|
|
80
45
|
class Deedrah < Sinatra::Base
|
@@ -204,14 +169,14 @@ module ThmUI extend self
|
|
204
169
|
query = "select count(*) as num2, ip_dst from wifi_ippacket a JOIN wifi_#{proto}packet b on (a.guid = b.guid) JOIN service_definitions s on (s.num = b.#{proto}_dport) where #{proto}_dport > 0 and #{proto}_dport < 10000 and s.protocol = '#{proto.upcase}' and ip_dst not in ('255.255.255.255') group by b.#{proto}_dport, a.ip_dst;"
|
205
170
|
resusrcnt = @sessobj.query("#{query}")
|
206
171
|
rowusrcnt = Array.new
|
207
|
-
@gcnt =
|
172
|
+
@gcnt = Keycounter.new
|
208
173
|
while row = resusrcnt.fetch_hash do
|
209
174
|
num2 = row["num2"].to_s
|
210
175
|
ip_dst = row["ip_dst"].to_s
|
211
176
|
location = geoiplookup(ip_dst)
|
212
177
|
locfix = location.to_s.gsub("(", "").gsub(")", "") # Yawn
|
213
178
|
if location != nil or location == "" # You can't have a blank or nil instance_variable
|
214
|
-
@gcnt.
|
179
|
+
@gcnt.keycount("#{locfix}")
|
215
180
|
end
|
216
181
|
rowusrcnt << ["#{ip_dst} #{location}", "#{num2}"]
|
217
182
|
end
|
@@ -259,7 +224,7 @@ module ThmUI extend self
|
|
259
224
|
@rowusrcnt5 = toptalkers("udp")
|
260
225
|
# Top UDP/IP Talkers
|
261
226
|
@rowusrcnt6 = toptalkers("tcp")
|
262
|
-
@rowgeocount = @gcnt.
|
227
|
+
@rowgeocount = @gcnt.keycount_compile
|
263
228
|
puts "Geo Data:"
|
264
229
|
@rowgeocount.each {|n, x|
|
265
230
|
puts "#{n} #{x}"
|
data/bin/thm-trafviz
CHANGED
@@ -15,6 +15,7 @@ require 'walltime'
|
|
15
15
|
require 'readline'
|
16
16
|
require 'mymenu'
|
17
17
|
require 'pp'
|
18
|
+
require 'cgi'
|
18
19
|
|
19
20
|
require File.expand_path(File.join(
|
20
21
|
File.dirname(__FILE__),
|
@@ -80,6 +81,7 @@ opts = GetoptLong.new(
|
|
80
81
|
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
81
82
|
[ '--interface', '-i', GetoptLong::OPTIONAL_ARGUMENT],
|
82
83
|
[ '--snaplength', '-s', GetoptLong::OPTIONAL_ARGUMENT],
|
84
|
+
[ '--safebrowsing', '-b', GetoptLong::OPTIONAL_ARGUMENT],
|
83
85
|
[ '--debug', '-d', GetoptLong::NO_ARGUMENT ],
|
84
86
|
)
|
85
87
|
|
@@ -94,6 +96,8 @@ opts.each do |opt, arg|
|
|
94
96
|
|
95
97
|
-s, --snaplength - Snaplength [ OPTIONAL_ARGUMENT ]
|
96
98
|
|
99
|
+
-b, --safebrowsing - Enable Google Safebrowsing API for traffic categorization
|
100
|
+
|
97
101
|
-d --debug
|
98
102
|
|
99
103
|
]
|
@@ -106,6 +110,8 @@ opts.each do |opt, arg|
|
|
106
110
|
@interface = nil || arg
|
107
111
|
when '--snaplength'
|
108
112
|
@snaplength = nil || arg
|
113
|
+
when '--safebrowsing'
|
114
|
+
@safebrowsing_enabled = nil || arg
|
109
115
|
end
|
110
116
|
end
|
111
117
|
|
@@ -113,13 +119,14 @@ puts banner
|
|
113
119
|
|
114
120
|
# Trafviz DataServices
|
115
121
|
tv = Thm::DataServices::Trafviz.new
|
122
|
+
tv.debug = @debug
|
116
123
|
tv.reqtable = HTTP_REQUEST_TABLE
|
117
124
|
tv.reqtableua = HTTP_REQUEST_TABLE_UA
|
118
125
|
# Connect to Datastore
|
119
126
|
gloc = Thm::DataServices::Geolocation.new
|
120
127
|
gloc.datastore = DATASTORE
|
121
|
-
gloc.debug =
|
122
|
-
gloc.autocommit =
|
128
|
+
gloc.debug = 0
|
129
|
+
gloc.autocommit = false
|
123
130
|
gloc.dbhost = DBHOST
|
124
131
|
gloc.dbuser = DBUSER
|
125
132
|
gloc.dbpass = DBPASS
|
@@ -128,152 +135,12 @@ gloc.dbconnect
|
|
128
135
|
|
129
136
|
use_const_defined_unless?("INTERFACE")
|
130
137
|
use_const_defined_unless?("SNAPLENGTH")
|
138
|
+
use_const_defined_unless?("SAFEBROWSING_ENABLED")
|
131
139
|
|
132
140
|
startup = "-s #{@snaplength} -n -i #{@interface}"
|
133
141
|
puts "Trafviz - Startup Parameters: #{startup}"
|
142
|
+
puts "Safebrowsing URL: #{SAFEBROWSING_URL}" unless @safebrowsing_enabled == "false"
|
134
143
|
|
135
|
-
module Thm
|
136
|
-
|
137
|
-
class DataServices::Trafviz::FilterManager
|
138
|
-
|
139
|
-
attr_reader :bookmarks, :pcapsetfilter
|
140
|
-
|
141
|
-
def initialize
|
142
|
-
@bookmarks = Array.new
|
143
|
-
@bkm = MyMenu.new
|
144
|
-
@bkm.settitle("Welcome to Trafviz")
|
145
|
-
@bkm.mymenuname = "Trafviz"
|
146
|
-
@bkm.prompt = "Trafviz"
|
147
|
-
@pcapsetfilter = String.new
|
148
|
-
end
|
149
|
-
|
150
|
-
def read(file)
|
151
|
-
b = 0
|
152
|
-
File.open("#{Dir.home}/.thm/#{file}", 'r') {|n|
|
153
|
-
n.each_line {|l|
|
154
|
-
puts "\e[1;36m#{b})\e[0m\ #{l}"
|
155
|
-
@bookmarks[b] = l
|
156
|
-
b += 1
|
157
|
-
}
|
158
|
-
}
|
159
|
-
end
|
160
|
-
|
161
|
-
def write(file)
|
162
|
-
@bkm.mymenuname = "Filters"
|
163
|
-
@bkm.prompt = "\e[1;33m\Set filter>\e[0m\ "
|
164
|
-
pcapfilter = @bkm.definemenuitem("selectfilter", true) do
|
165
|
-
# Just needs value returned via readline block into addfilter
|
166
|
-
end
|
167
|
-
fltvalid = validate_filter?("#{pcapfilter}")
|
168
|
-
if fltvalid == true
|
169
|
-
File.open("#{Dir.home}/.thm/#{file}", 'a') {|n| # Append to filter file
|
170
|
-
n.puts("#{addfilter}")
|
171
|
-
}
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def set_defaults(file)
|
176
|
-
# Add default example filters
|
177
|
-
File.open("#{Dir.home}/.thm/#{file}", 'w') {|n|
|
178
|
-
n.puts("webtraffic: tcp dst port 80")
|
179
|
-
n.puts("sourceportrange: tcp src portrange 1024-65535")
|
180
|
-
}
|
181
|
-
end
|
182
|
-
|
183
|
-
def validate_filter?(filter)
|
184
|
-
begin
|
185
|
-
Pcap::Filter.compile("#{filter}")
|
186
|
-
puts "Filter Compile #{filter}"
|
187
|
-
return true
|
188
|
-
rescue Pcap::PcapError => e
|
189
|
-
pp e
|
190
|
-
return false
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
def build_filter_menu
|
195
|
-
@bkm.settitle("Welcome to Trafviz")
|
196
|
-
@bkm.mymenuname = "Trafviz"
|
197
|
-
@bkm.prompt = "Trafviz"
|
198
|
-
@bkm.debug = 3
|
199
|
-
pp @bookmarks
|
200
|
-
@bookmarks.each {|n|
|
201
|
-
func_name = n.split(":")[0]
|
202
|
-
pcap_filter = n.split(":")[1].lstrip
|
203
|
-
puts "#{pcap_filter}"
|
204
|
-
# Instance Eval probably nicer
|
205
|
-
fltvalid = validate_filter?("#{pcap_filter}") # Because validate_filter? won't exist inside instance_eval
|
206
|
-
@bkm.instance_eval do
|
207
|
-
pp fltvalid
|
208
|
-
if fltvalid == true
|
209
|
-
definemenuitem("#{func_name}") do
|
210
|
-
@pcapsetfilter = "#{pcap_filter}"
|
211
|
-
#thm = DataServices::Trafviz::Main.new
|
212
|
-
end
|
213
|
-
additemtolist("#{func_name}: #{pcap_filter}", "#{func_name};")
|
214
|
-
end
|
215
|
-
end
|
216
|
-
}
|
217
|
-
@bkm.instance_eval do
|
218
|
-
definemenuitem("showfilter") do
|
219
|
-
puts "Filter: #{@pcapsetfilter}"
|
220
|
-
end
|
221
|
-
additemtolist("Show Current Filter", "showfilter;")
|
222
|
-
end
|
223
|
-
@bkm.additemtolist("Display Menu", "showmenu;")
|
224
|
-
@bkm.additemtolist("Toggle Menu", "togglemenu;")
|
225
|
-
@bkm.additemtolist("Exit Trafviz", "exit;")
|
226
|
-
@bkm.menu!
|
227
|
-
end
|
228
|
-
|
229
|
-
def load_filters(file)
|
230
|
-
if File.exists?("#{Dir.home}/.thm/#{file}")
|
231
|
-
read(file)
|
232
|
-
else
|
233
|
-
set_defaults(file)
|
234
|
-
read(file)
|
235
|
-
end
|
236
|
-
build_filter_menu
|
237
|
-
end
|
238
|
-
|
239
|
-
end
|
240
|
-
|
241
|
-
end
|
242
|
-
|
243
|
-
# Main class / Startup
|
244
|
-
|
245
|
-
module Thm
|
246
|
-
|
247
|
-
class DataServices::Trafviz::Main
|
248
|
-
|
249
|
-
attr_accessor :startup
|
250
|
-
|
251
|
-
def initialize
|
252
|
-
@filter_const = Array.new
|
253
|
-
@startup = String.new
|
254
|
-
@thm = Thm::DataServices::Trafviz::FilterManager.new
|
255
|
-
end
|
256
|
-
|
257
|
-
def addfilter(const, filter)
|
258
|
-
if @thm.validate_filter?(filter) == true
|
259
|
-
filtercode = %Q{#{const} = Pcap::Filter.new('#{filter}', @trafviz.capture)}
|
260
|
-
@filter_const << "#{const})"
|
261
|
-
eval(filtercode)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def commitfilters
|
266
|
-
flts = @filter_const.join(" | ") # Build string of CONST names
|
267
|
-
commitcode = %Q{@trafviz.add_filter(#{flts})}
|
268
|
-
eval(flts)
|
269
|
-
end
|
270
|
-
|
271
|
-
def run!
|
272
|
-
@trafviz = Pcaplet.new(@startup)
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
end
|
277
144
|
=begin
|
278
145
|
FILTERLIST = 'filters.lst'
|
279
146
|
a = Thm::DataServices::Trafviz::FilterManager.new
|
@@ -291,6 +158,8 @@ a.menu!
|
|
291
158
|
HTTP_REQUEST = Pcap::Filter.new('tcp dst port 80', @trafviz.capture)
|
292
159
|
HTTP_RESPONSE = Pcap::Filter.new('tcp src portrange 1024-65535', @trafviz.capture)
|
293
160
|
|
161
|
+
@sb = Thm::DataServices::Safebrowsing.new unless @safebrowsing_enabled == "false"
|
162
|
+
|
294
163
|
@trafviz.add_filter(HTTP_REQUEST | HTTP_RESPONSE)
|
295
164
|
@trafviz.each_packet {|pkt|
|
296
165
|
data = pkt.tcp_data.to_s
|
@@ -308,6 +177,11 @@ HTTP_RESPONSE = Pcap::Filter.new('tcp src portrange 1024-65535', @trafviz.captur
|
|
308
177
|
puts "\e[4;36mGeo Location:\e[0m\ \n\e[0;35m#{geo} \e[0m\ "
|
309
178
|
puts "\e[4;36mRequest Data:\e[0m\ \n\e[0;32m#{data_highlight} \e[0m\ "
|
310
179
|
tv.makeurl(data_orig)
|
180
|
+
makeurl_last = CGI.escape(tv.makeurl_last)
|
181
|
+
if instance_variable_defined?("@sb")
|
182
|
+
@sb.debug = @debug
|
183
|
+
@sb.lookup("#{SAFEBROWSING_URL}#{makeurl_last}")
|
184
|
+
end
|
311
185
|
# Process data and prepare then send elsewhere
|
312
186
|
query_return_sql = tv.request_filter(data)
|
313
187
|
# Store data into Datastore
|
@@ -319,7 +193,7 @@ HTTP_RESPONSE = Pcap::Filter.new('tcp src portrange 1024-65535', @trafviz.captur
|
|
319
193
|
end
|
320
194
|
}
|
321
195
|
rescue
|
322
|
-
Tools::log_errors("/tmp/thm-sql-errors.log", "SQL Error - #{Time.now} - #{query_return_sql}")
|
196
|
+
Tools::log_errors("/tmp/thm-sql-errors.log", "SQL Error - #{Time.now} - #{query_return_sql}") unless query_return_sql == "SELECT 1;"
|
323
197
|
end
|
324
198
|
stwt.watch('stop')
|
325
199
|
stwt.print_stats
|
@@ -338,4 +212,11 @@ HTTP_RESPONSE = Pcap::Filter.new('tcp src portrange 1024-65535', @trafviz.captur
|
|
338
212
|
end
|
339
213
|
end
|
340
214
|
puts s.gsub("GET", "\e[1;36mGET\e[0m").gsub("POST", "\e[1;36mPOST\e[0m") if s
|
215
|
+
|
216
|
+
# Just so we don't loose any data between commits on exiting...
|
217
|
+
trap("INT") {
|
218
|
+
gloc.commit
|
219
|
+
exit
|
220
|
+
}
|
221
|
+
|
341
222
|
}
|
data/bin/thm-useradmin
CHANGED
data/config.rb
CHANGED
@@ -31,11 +31,24 @@ module Thm
|
|
31
31
|
HTTP_REQUEST_TABLE = "http_traffic_json"
|
32
32
|
HTTP_RESPONSE_TABLE = "http_traffic_json"
|
33
33
|
HTTP_REQUEST_TABLE_UA = "http_traffic_ua"
|
34
|
-
|
34
|
+
# Common HTTP / HTTPS data ports for Trafviz
|
35
|
+
HTTP_PORTS = [80, 3128, 8000, 8080, 8088, 8888]
|
36
|
+
HTTPS_PORTS = [443, 444, 3129, 8443]
|
37
|
+
|
35
38
|
# Misc
|
36
39
|
SNAPLENGTH = 65536
|
37
40
|
INTERFACE = "eth0"
|
41
|
+
|
42
|
+
# Google Safe Browsing API
|
43
|
+
SAFEBROWSING_ENABLED = "false"
|
44
|
+
SAFEBROWSING_API_KEY = "12345"
|
45
|
+
GOOGLE_API_PROJECTNAME = "myproject"
|
46
|
+
SAFEBROWSING_URL = "https://sb-ssl.google.com/safebrowsing/api/lookup?client=#{GOOGLE_API_PROJECTNAME}&key=#{SAFEBROWSING_API_KEY}&appver=1.5.2&pver=3.1&url="
|
38
47
|
|
48
|
+
GEOCODING_ENABLED = "false"
|
49
|
+
GEOCODING_API_KEY = "12345"
|
50
|
+
GEOCODING_URL = "https://maps.googleapis.com/maps/api/geocode/json?key=#{GEOCODING_API_KEY}&" # Format: "latlng=40.714224,-73.961452"
|
51
|
+
|
39
52
|
end
|
40
53
|
|
41
54
|
end
|
data/lib/thm.rb
CHANGED
@@ -27,6 +27,126 @@ class String
|
|
27
27
|
|
28
28
|
end
|
29
29
|
|
30
|
+
|
31
|
+
# Slight patch here
|
32
|
+
# Needs to moving to monkeypatches.rb
|
33
|
+
|
34
|
+
class MonetDBConnection
|
35
|
+
|
36
|
+
# perform a real connection; retrieve challenge, proxy through merovinginan, build challenge and set the timezone
|
37
|
+
def real_connect
|
38
|
+
|
39
|
+
server_challenge = retrieve_server_challenge()
|
40
|
+
if server_challenge != nil
|
41
|
+
salt = server_challenge.split(':')[0]
|
42
|
+
@server_name = server_challenge.split(':')[1]
|
43
|
+
@protocol = server_challenge.split(':')[2].to_i
|
44
|
+
@supported_auth_types = server_challenge.split(':')[3].split(',')
|
45
|
+
@server_endianness = server_challenge.split(':')[4]
|
46
|
+
=begin
|
47
|
+
Causes issues with Threatmonitor
|
48
|
+
#if @@SUPPORTED_PROTOCOLS.include?(@protocol) == False
|
49
|
+
# raise MonetDBProtocolError, "Protocol not supported. The current implementation of ruby-monetdb works with MAPI protocols #{@@SUPPORTED_PROTOCOLS} only."
|
50
|
+
#end
|
51
|
+
=end
|
52
|
+
@pwhash = server_challenge.split(':')[5]
|
53
|
+
else
|
54
|
+
raise MonetDBConnectionError, "Error: server returned an empty challenge string."
|
55
|
+
end
|
56
|
+
|
57
|
+
# The server supports only RIPMED160 or crypt as an authentication hash function, but the driver does not.
|
58
|
+
if @supported_auth_types.length == 1
|
59
|
+
auth = @supported_auth_types[0]
|
60
|
+
if auth.upcase == "RIPEMD160"
|
61
|
+
raise MonetDBConnectionError, auth.upcase + " " + ": algorithm not supported by ruby-monetdb."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
reply = build_auth_string_v9(@auth_type, salt, @database)
|
66
|
+
|
67
|
+
if @socket != nil
|
68
|
+
@connection_established = true
|
69
|
+
|
70
|
+
send(reply)
|
71
|
+
monetdb_auth = receive
|
72
|
+
|
73
|
+
if monetdb_auth.length == 0
|
74
|
+
# auth succedeed
|
75
|
+
true
|
76
|
+
else
|
77
|
+
if monetdb_auth[0].chr == MSG_REDIRECT
|
78
|
+
#redirection
|
79
|
+
|
80
|
+
redirects = [] # store a list of possible redirects
|
81
|
+
|
82
|
+
monetdb_auth.split('\n').each do |m|
|
83
|
+
# strip the trailing ^mapi:
|
84
|
+
# if the redirect string start with something != "^mapi:" or is empty, the redirect is invalid and shall not be included.
|
85
|
+
if m[0..5] == "^mapi:"
|
86
|
+
redir = m[6..m.length]
|
87
|
+
# url parse redir
|
88
|
+
redirects.push(redir)
|
89
|
+
else
|
90
|
+
$stderr.print "Warning: Invalid Redirect #{m}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
if redirects.size == 0
|
95
|
+
raise MonetDBConnectionError, "No valid redirect received"
|
96
|
+
else
|
97
|
+
begin
|
98
|
+
uri = URI.split(redirects[0])
|
99
|
+
# Splits the string on following parts and returns array with result:
|
100
|
+
#
|
101
|
+
# * Scheme
|
102
|
+
# * Userinfo
|
103
|
+
# * Host
|
104
|
+
# * Port
|
105
|
+
# * Registry
|
106
|
+
# * Path
|
107
|
+
# * Opaque
|
108
|
+
# * Query
|
109
|
+
# * Fragment
|
110
|
+
server_name = uri[0]
|
111
|
+
host = uri[2]
|
112
|
+
port = uri[3]
|
113
|
+
database = uri[5].gsub(/^\//, '') if uri[5] != nil
|
114
|
+
rescue URI::InvalidURIError
|
115
|
+
raise MonetDBConnectionError, "Invalid redirect: #{redirects[0]}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if server_name == MONETDB_MEROVINGIAN
|
120
|
+
if @auth_iteration <= MEROVINGIAN_MAX_ITERATIONS
|
121
|
+
@auth_iteration += 1
|
122
|
+
real_connect
|
123
|
+
else
|
124
|
+
raise MonetDBConnectionError, "Merovingian: too many iterations while proxying."
|
125
|
+
end
|
126
|
+
elsif server_name == MONETDB_MSERVER
|
127
|
+
begin
|
128
|
+
@socket.close
|
129
|
+
rescue
|
130
|
+
raise MonetDBConnectionError, "I/O error while closing connection to #{@socket}"
|
131
|
+
end
|
132
|
+
# reinitialize a connection
|
133
|
+
@host = host
|
134
|
+
@port = port
|
135
|
+
|
136
|
+
connect(database, @auth_type)
|
137
|
+
else
|
138
|
+
@connection_established = false
|
139
|
+
raise MonetDBConnectionError, monetdb_auth
|
140
|
+
end
|
141
|
+
elsif monetdb_auth[0].chr == MSG_INFO
|
142
|
+
raise MonetDBConnectionError, monetdb_auth
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
30
150
|
module Tools
|
31
151
|
|
32
152
|
class << self
|
@@ -56,12 +176,12 @@ module Tools
|
|
56
176
|
def use_const_defined_unless?(const)
|
57
177
|
const_down = const.downcase
|
58
178
|
if Kernel.const_defined?("#{const}")
|
59
|
-
|
179
|
+
unless instance_variable_defined?("@#{const_down}")
|
60
180
|
instance_variable_set("@#{const_down}", Kernel.const_get("#{const}"))
|
61
181
|
puts "Config Constant #{const}: #{Kernel.const_get("#{const}")}"
|
62
182
|
puts "Instance Variable @#{const_down}: #{instance_variable_get("@#{const_down}")}"
|
63
183
|
else
|
64
|
-
puts "Param via Getoptlong: Instance Variable
|
184
|
+
puts "Param via Getoptlong: Instance Variable @#{const_down}: #{instance_variable_get("@#{const_down}")}"
|
65
185
|
end
|
66
186
|
else
|
67
187
|
raise "No Config option set add #{const} to your config.rb"
|
@@ -70,6 +190,24 @@ module Tools
|
|
70
190
|
|
71
191
|
end
|
72
192
|
|
193
|
+
module TextProcessing
|
194
|
+
|
195
|
+
|
196
|
+
def text_highlighter(text)
|
197
|
+
keys = ["Linux", "Java", "Android", "iPhone", "Mobile", "Chrome",
|
198
|
+
"Safari", "Mozilla", "Gecko", "AppleWebKit", "Windows",
|
199
|
+
"MSIE", "Win64", "Trident", "wispr", "PHPSESSID", "JSESSIONID",
|
200
|
+
"AMD64", "Darwin", "Macintosh", "Mac OS X", "Dalvik", "text/html", "xml"]
|
201
|
+
cpicker = [2,3,4,1,7,5,6] # Just a selection of colours
|
202
|
+
keys.each {|n|
|
203
|
+
text.gsub!("#{n}", "\e[4;3#{cpicker[rand(cpicker.size)]}m#{n}\e[0m\ \e[0;32m".strip)
|
204
|
+
}
|
205
|
+
return text
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
end
|
210
|
+
|
73
211
|
# Load Database drivers
|
74
212
|
require File.expand_path(File.join(
|
75
213
|
File.dirname(__FILE__),
|