thm 0.4.5 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- 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__),
|