sqreen 0.8.11465220943 → 1.0.0.pre1480953244
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sqreen.rb +0 -1
- data/lib/sqreen/binding_accessor.rb +61 -49
- data/lib/sqreen/condition_evaluator.rb +17 -12
- data/lib/sqreen/conditionable.rb +2 -1
- data/lib/sqreen/configuration.rb +2 -0
- data/lib/sqreen/deliveries/batch.rb +2 -2
- data/lib/sqreen/events/attack.rb +1 -1
- data/lib/sqreen/frameworks/generic.rb +54 -15
- data/lib/sqreen/frameworks/rails.rb +1 -21
- data/lib/sqreen/frameworks/sinatra.rb +5 -0
- data/lib/sqreen/instrumentation.rb +7 -10
- data/lib/sqreen/log.rb +1 -0
- data/lib/sqreen/metrics/base.rb +4 -0
- data/lib/sqreen/metrics_store.rb +4 -4
- data/lib/sqreen/remote_command.rb +5 -4
- data/lib/sqreen/rules_callbacks.rb +0 -4
- data/lib/sqreen/rules_callbacks/matcher_rule.rb +8 -6
- data/lib/sqreen/rules_callbacks/reflected_xss.rb +55 -11
- data/lib/sqreen/runner.rb +76 -73
- data/lib/sqreen/runtime_infos.rb +3 -2
- data/lib/sqreen/serializer.rb +46 -0
- data/lib/sqreen/session.rb +22 -12
- data/lib/sqreen/version.rb +1 -1
- metadata +6 -14
- data/lib/sqreen/detect.rb +0 -14
- data/lib/sqreen/detect/shell_injection.rb +0 -61
- data/lib/sqreen/detect/sql_injection.rb +0 -115
- data/lib/sqreen/parsers/sql.rb +0 -98
- data/lib/sqreen/parsers/sql_tokenizer.rb +0 -266
- data/lib/sqreen/parsers/unix.rb +0 -110
- data/lib/sqreen/rules_callbacks/shell.rb +0 -33
- data/lib/sqreen/rules_callbacks/sql.rb +0 -41
- data/lib/sqreen/rules_callbacks/system_shell.rb +0 -25
data/lib/sqreen/runtime_infos.rb
CHANGED
@@ -45,7 +45,8 @@ module Sqreen
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def time
|
48
|
-
|
48
|
+
# FIXME: That should maybe be called local-time
|
49
|
+
{ :time => Time.now }
|
49
50
|
end
|
50
51
|
|
51
52
|
def ssl
|
@@ -120,7 +121,7 @@ module Sqreen
|
|
120
121
|
ret['remotes'] = opts['remotes'] if opts['remotes']
|
121
122
|
ret['uri'] = opts['uri'] if opts['uri']
|
122
123
|
# FIXME: scrub any auth data in uris
|
123
|
-
ret['path'] = opts['path'] if opts['path']
|
124
|
+
ret['path'] = opts['path'].to_s if opts['path']
|
124
125
|
ret
|
125
126
|
end
|
126
127
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
module Sqreen
|
5
|
+
# Serialization functions: convert Hash -> simple ruby types
|
6
|
+
module Serializer
|
7
|
+
# Serialize a deep hash/array to more simple types
|
8
|
+
def self.serialize(obj, max_depth = 10)
|
9
|
+
if obj.is_a?(Array)
|
10
|
+
new_obj = []
|
11
|
+
i = -1
|
12
|
+
to_do = obj.map { |v| [new_obj, i += 1, v, 0] }
|
13
|
+
else
|
14
|
+
new_obj = {}
|
15
|
+
to_do = obj.map { |k, v| [new_obj, k, v, 0] }
|
16
|
+
end
|
17
|
+
until to_do.empty?
|
18
|
+
where, key, value, deepness = to_do.pop
|
19
|
+
safe_key = key.kind_of?(Integer) ? key : key.to_s
|
20
|
+
if value.is_a?(Hash) && deepness < max_depth
|
21
|
+
where[safe_key] = {}
|
22
|
+
to_do += value.map { |k, v| [where[safe_key], k, v, deepness + 1] }
|
23
|
+
elsif value.is_a?(Array) && deepness < max_depth
|
24
|
+
where[safe_key] = []
|
25
|
+
i = -1
|
26
|
+
to_do += value.map { |v| [where[safe_key], i += 1, v, deepness + 1] }
|
27
|
+
else
|
28
|
+
case value
|
29
|
+
when Symbol
|
30
|
+
where[safe_key] = value.to_s
|
31
|
+
when Rational
|
32
|
+
where[safe_key] = value.to_f
|
33
|
+
when Time
|
34
|
+
where[safe_key] = value.iso8601
|
35
|
+
when Numeric, String, TrueClass, FalseClass, NilClass
|
36
|
+
where[safe_key] = value
|
37
|
+
else
|
38
|
+
where[safe_key] = "#{value.class.name}:#{value.inspect}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
new_obj
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/sqreen/session.rb
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
require 'sqreen/log'
|
5
|
+
require 'sqreen/serializer'
|
5
6
|
require 'sqreen/runtime_infos'
|
6
7
|
require 'sqreen/events/remote_exception'
|
8
|
+
require 'sqreen/exception'
|
7
9
|
|
8
10
|
require 'net/https'
|
9
11
|
require 'json'
|
@@ -46,6 +48,7 @@ module Sqreen
|
|
46
48
|
@server_url = server_url
|
47
49
|
@request_compression = false
|
48
50
|
@connected = nil
|
51
|
+
@con = nil
|
49
52
|
|
50
53
|
uri = parse_uri(server_url)
|
51
54
|
use_ssl = (uri.scheme == 'https')
|
@@ -71,6 +74,7 @@ module Sqreen
|
|
71
74
|
end
|
72
75
|
|
73
76
|
def prefix_path(path)
|
77
|
+
return '/sqreen/v1/' + path if path == 'app-login' || path == 'app-beat'
|
74
78
|
@@path_prefix + path
|
75
79
|
end
|
76
80
|
|
@@ -180,7 +184,11 @@ module Sqreen
|
|
180
184
|
when :GET
|
181
185
|
@con.get(path, headers)
|
182
186
|
when :POST
|
183
|
-
json_data =
|
187
|
+
json_data = nil
|
188
|
+
unless data.nil?
|
189
|
+
serialized = Serializer.serialize(data)
|
190
|
+
json_data = compress(self.class.encode_payload(serialized))
|
191
|
+
end
|
184
192
|
@con.post(path, json_data, headers)
|
185
193
|
else
|
186
194
|
Sqreen.log.debug format('unknown method %s', method)
|
@@ -203,7 +211,7 @@ module Sqreen
|
|
203
211
|
|
204
212
|
def self.encode_payload(data)
|
205
213
|
JSON.generate(data)
|
206
|
-
rescue JSON::GeneratorError
|
214
|
+
rescue JSON::GeneratorError, Encoding::UndefinedConversionError
|
207
215
|
Sqreen.log.debug('Payload could not be encoded enforcing recode')
|
208
216
|
JSON.generate(rencode_payload(data))
|
209
217
|
end
|
@@ -242,12 +250,14 @@ module Sqreen
|
|
242
250
|
|
243
251
|
def self.enforce_encoding(str)
|
244
252
|
return str unless str.is_a?(String)
|
245
|
-
return str if str.
|
253
|
+
return str if str.ascii_only?
|
254
|
+
encoded8bit = str.encoding.name == 'ASCII-8BIT'
|
255
|
+
return str if !encoded8bit && str.valid_encoding?
|
246
256
|
str.chars.map do |v|
|
247
|
-
if v.valid_encoding?
|
248
|
-
v
|
249
|
-
else
|
257
|
+
if !v.valid_encoding? || (encoded8bit && !v.ascii_only?)
|
250
258
|
v.bytes.map { |c| "\\x#{c.to_s(16).upcase}" }.join
|
259
|
+
else
|
260
|
+
v
|
251
261
|
end
|
252
262
|
end.join
|
253
263
|
end
|
@@ -267,19 +277,19 @@ module Sqreen
|
|
267
277
|
@session_id = res['session_id']
|
268
278
|
Sqreen.log.debug "received session_id #{@session_id}"
|
269
279
|
Sqreen.logged_in = true
|
270
|
-
res
|
280
|
+
res
|
271
281
|
end
|
272
282
|
|
273
283
|
def rules
|
274
284
|
resilient_get('rulespack')
|
275
285
|
end
|
276
286
|
|
277
|
-
def heartbeat
|
278
|
-
|
279
|
-
|
287
|
+
def heartbeat(cmd_res = {}, metrics = [])
|
288
|
+
payload = {}
|
289
|
+
payload['metrics'] = metrics unless metrics.nil? || metrics.empty?
|
290
|
+
payload['command_results'] = cmd_res unless cmd_res.nil? || cmd_res.empty?
|
280
291
|
|
281
|
-
|
282
|
-
resilient_post('commands', res)
|
292
|
+
post('app-beat', payload.empty? ? nil : payload, {}, 5)
|
283
293
|
end
|
284
294
|
|
285
295
|
def post_metrics(metrics)
|
data/lib/sqreen/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqreen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre1480953244
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sqreen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -60,9 +60,6 @@ files:
|
|
60
60
|
- lib/sqreen/context.rb
|
61
61
|
- lib/sqreen/deliveries/batch.rb
|
62
62
|
- lib/sqreen/deliveries/simple.rb
|
63
|
-
- lib/sqreen/detect.rb
|
64
|
-
- lib/sqreen/detect/shell_injection.rb
|
65
|
-
- lib/sqreen/detect/sql_injection.rb
|
66
63
|
- lib/sqreen/event.rb
|
67
64
|
- lib/sqreen/events/attack.rb
|
68
65
|
- lib/sqreen/events/remote_exception.rb
|
@@ -81,9 +78,6 @@ files:
|
|
81
78
|
- lib/sqreen/metrics/collect.rb
|
82
79
|
- lib/sqreen/metrics/sum.rb
|
83
80
|
- lib/sqreen/metrics_store.rb
|
84
|
-
- lib/sqreen/parsers/sql.rb
|
85
|
-
- lib/sqreen/parsers/sql_tokenizer.rb
|
86
|
-
- lib/sqreen/parsers/unix.rb
|
87
81
|
- lib/sqreen/payload_creator.rb
|
88
82
|
- lib/sqreen/performance_notifications.rb
|
89
83
|
- lib/sqreen/performance_notifications/log.rb
|
@@ -106,15 +100,13 @@ files:
|
|
106
100
|
- lib/sqreen/rules_callbacks/record_request_context.rb
|
107
101
|
- lib/sqreen/rules_callbacks/reflected_xss.rb
|
108
102
|
- lib/sqreen/rules_callbacks/regexp_rule.rb
|
109
|
-
- lib/sqreen/rules_callbacks/shell.rb
|
110
103
|
- lib/sqreen/rules_callbacks/shell_env.rb
|
111
|
-
- lib/sqreen/rules_callbacks/sql.rb
|
112
|
-
- lib/sqreen/rules_callbacks/system_shell.rb
|
113
104
|
- lib/sqreen/rules_callbacks/url_matches.rb
|
114
105
|
- lib/sqreen/rules_callbacks/user_agent_matches.rb
|
115
106
|
- lib/sqreen/rules_signature.rb
|
116
107
|
- lib/sqreen/runner.rb
|
117
108
|
- lib/sqreen/runtime_infos.rb
|
109
|
+
- lib/sqreen/serializer.rb
|
118
110
|
- lib/sqreen/session.rb
|
119
111
|
- lib/sqreen/stats.rb
|
120
112
|
- lib/sqreen/version.rb
|
@@ -132,12 +124,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
124
|
version: '0'
|
133
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
126
|
requirements:
|
135
|
-
- - "
|
127
|
+
- - ">"
|
136
128
|
- !ruby/object:Gem::Version
|
137
|
-
version:
|
129
|
+
version: 1.3.1
|
138
130
|
requirements: []
|
139
131
|
rubyforge_project:
|
140
|
-
rubygems_version: 2.
|
132
|
+
rubygems_version: 2.5.1
|
141
133
|
signing_key:
|
142
134
|
specification_version: 4
|
143
135
|
summary: Sqreen Ruby agent
|
data/lib/sqreen/detect.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
-
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
-
|
4
|
-
require 'sqreen/detect/sql_injection'
|
5
|
-
require 'sqreen/detect/shell_injection'
|
6
|
-
|
7
|
-
module Sqreen
|
8
|
-
module Detect
|
9
|
-
def sql_injection?(request, params, db_type, db_infos = {})
|
10
|
-
inj = SQLInjection.new(db_type, db_infos)
|
11
|
-
inj.user_escape?(request, params)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
-
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
-
|
4
|
-
require 'sqreen/parsers/unix'
|
5
|
-
|
6
|
-
module Sqreen
|
7
|
-
module Detect
|
8
|
-
# Detector class for shell injections
|
9
|
-
# Find instance of user parameters injections into executable commands
|
10
|
-
# It work by:
|
11
|
-
# 1 - Highlighting the cmd for executable sections
|
12
|
-
# 2 - Highlighting the cmd for traces of user parameters
|
13
|
-
# 3 - Comparing if there is any intersection
|
14
|
-
class ShellInjection
|
15
|
-
def initialize
|
16
|
-
@parser = Sqreen::Parsers::Unix.new
|
17
|
-
end
|
18
|
-
|
19
|
-
# Is there a user injection in cmd
|
20
|
-
# @param cmd [String] command to analyze
|
21
|
-
# @param params [Hash] Hash of user parameters
|
22
|
-
def user_escape?(cmd, params)
|
23
|
-
Sqreen.log.info format('escape? %s', [cmd, params].inspect)
|
24
|
-
|
25
|
-
# We found the user query inside the cmd. A risk exists.
|
26
|
-
@parser.parse(cmd)
|
27
|
-
execs = @parser.atoms.select(&:executable?)
|
28
|
-
|
29
|
-
each_param_scalar(params) do |v|
|
30
|
-
next unless v
|
31
|
-
value = v.to_s
|
32
|
-
next unless value.size > 0
|
33
|
-
offset = 0
|
34
|
-
loop do
|
35
|
-
match_start = cmd.index(value, offset)
|
36
|
-
break if match_start.nil?
|
37
|
-
match_end = match_start + value.size
|
38
|
-
offset = match_end
|
39
|
-
covered = execs.any? do |exec|
|
40
|
-
match_end >= exec.start && match_start < exec.end
|
41
|
-
end
|
42
|
-
next unless covered
|
43
|
-
Sqreen.log.info format('injection for parameter %s', value.inspect)
|
44
|
-
return true
|
45
|
-
end
|
46
|
-
end
|
47
|
-
false
|
48
|
-
end
|
49
|
-
|
50
|
-
# FIXME: deduplicate code
|
51
|
-
def each_param_scalar(params, &block)
|
52
|
-
case params
|
53
|
-
when Hash then params.each { |_k, v| each_param_scalar(v, &block) }
|
54
|
-
when Array then params.each { |v| each_param_scalar(v, &block) }
|
55
|
-
else
|
56
|
-
yield params
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,115 +0,0 @@
|
|
1
|
-
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
-
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
-
|
4
|
-
require 'sqreen/parsers/sql'
|
5
|
-
require 'strscan'
|
6
|
-
|
7
|
-
module Sqreen
|
8
|
-
module Detect
|
9
|
-
class SQLInjection
|
10
|
-
PARAM_SIZE_LIMIT = 0
|
11
|
-
|
12
|
-
def self.parser(db_type, db_infos)
|
13
|
-
@parsers ||= {}
|
14
|
-
res = nil
|
15
|
-
results = @parsers[db_type]
|
16
|
-
res = results.find { |infos, _| infos == db_infos } unless results.nil?
|
17
|
-
return res.last unless res.nil?
|
18
|
-
@parsers[db_type] ||= []
|
19
|
-
parser = Sqreen::Parsers::SQL.new(db_type, db_infos)
|
20
|
-
@parsers[db_type] << [db_infos, parser]
|
21
|
-
parser
|
22
|
-
end
|
23
|
-
|
24
|
-
attr_accessor :db_type, :db_infos
|
25
|
-
def initialize(db_type, db_infos)
|
26
|
-
@db_type = db_type
|
27
|
-
@db_infos = db_infos
|
28
|
-
@parser = SQLInjection.parser(db_type, db_infos)
|
29
|
-
end
|
30
|
-
|
31
|
-
# FIXME: we are likely to find false postive
|
32
|
-
# As is, high risk of false positive with extremely short parameters.
|
33
|
-
# E.g. if parameter value is 'e', it will be found in request, (e in
|
34
|
-
# select) but not in literals.
|
35
|
-
#
|
36
|
-
# We may want to skip:
|
37
|
-
# - too short parameters (e.g. < 10 letters?)
|
38
|
-
# - non suspicious parameters (e.g. without blanks or comments?)
|
39
|
-
def user_escape?(request, params)
|
40
|
-
included = count_user_params_in_request(request, params)
|
41
|
-
return false if included == {}
|
42
|
-
|
43
|
-
escape_found = false
|
44
|
-
|
45
|
-
# We found the user query inside the request. A risk exists.
|
46
|
-
@parser.parse(request)
|
47
|
-
literals = @parser.atoms.select(&:is_literal?)
|
48
|
-
included.each do |param, expected_count|
|
49
|
-
param_count = 0
|
50
|
-
literals.each do |literal|
|
51
|
-
# Count number of literals that fully include the user query
|
52
|
-
param_count += count_substring_nb(literal.val, param)
|
53
|
-
end
|
54
|
-
|
55
|
-
# puts "%s in raw request: %d, in atoms: %d" % [param, expected_count, param_count]
|
56
|
-
next unless param_count != expected_count
|
57
|
-
Sqreen.log.info format('injection for parameter %s', param.inspect)
|
58
|
-
# require request aborption
|
59
|
-
# log attack
|
60
|
-
escape_found = true
|
61
|
-
end
|
62
|
-
escape_found
|
63
|
-
end
|
64
|
-
|
65
|
-
# What if a string can be prefixed itself?
|
66
|
-
# E.g. substr = 'a b c a b c'
|
67
|
-
# If str = 'a b c a b c a b c' we will return 2:
|
68
|
-
# \----1----/
|
69
|
-
# \----2----/
|
70
|
-
def count_substring_nb(str, substr)
|
71
|
-
s = StringScanner.new(str)
|
72
|
-
nb = 0
|
73
|
-
quote = Regexp.quote(substr)
|
74
|
-
re = Regexp.new(quote)
|
75
|
-
nb += 1 while s.search_full(re, true, false)
|
76
|
-
nb
|
77
|
-
end
|
78
|
-
|
79
|
-
def each_param_scalar(params, &block)
|
80
|
-
case params
|
81
|
-
when Hash then params.each { |_k, v| each_param_scalar(v, &block) }
|
82
|
-
when Array then params.each { |v| each_param_scalar(v, &block) }
|
83
|
-
else
|
84
|
-
yield params
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# FIXME: this work on params values. We might wnat to work on parameters
|
89
|
-
# names? High risk of false positive since a parameter name is often the
|
90
|
-
# database column name.
|
91
|
-
def count_user_params_in_request(request, params_hash)
|
92
|
-
res = {}
|
93
|
-
params_hash.each do |_type, params|
|
94
|
-
next if params.nil?
|
95
|
-
each_param_scalar(params) do |value|
|
96
|
-
next unless value
|
97
|
-
v = value.to_s
|
98
|
-
next if v.size <= PARAM_SIZE_LIMIT
|
99
|
-
next if v =~ /\A\.+\z/
|
100
|
-
next if v =~ /\A\s+\z/
|
101
|
-
next if v =~ /\A(\w+|\w[\w\.]+\w)\z/i
|
102
|
-
|
103
|
-
# We need to overwrite the count of equal parameters that
|
104
|
-
# came from different ways (e.g. Cookie and query).
|
105
|
-
next if res.key? v
|
106
|
-
nb = count_substring_nb(request, v)
|
107
|
-
|
108
|
-
res[v] = nb if nb > 0
|
109
|
-
end
|
110
|
-
end
|
111
|
-
res
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
data/lib/sqreen/parsers/sql.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
-
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
-
|
4
|
-
require 'sqreen/parsers/sql_tokenizer'
|
5
|
-
require 'sqreen/exception'
|
6
|
-
|
7
|
-
module Sqreen
|
8
|
-
module Parsers
|
9
|
-
# SELECT * FROM contacts WHERE name = #{name}
|
10
|
-
# name = 'a' 'b'
|
11
|
-
|
12
|
-
class SQLAtom
|
13
|
-
attr_reader :val, :type, :delim
|
14
|
-
def initialize(val, typ = :unkown, delim = nil, token_type = nil)
|
15
|
-
@val = val
|
16
|
-
@type = typ
|
17
|
-
@token_type = token_type
|
18
|
-
@delim = delim
|
19
|
-
end
|
20
|
-
|
21
|
-
def ==(other)
|
22
|
-
return false if other.nil?
|
23
|
-
@val == other.val &&
|
24
|
-
@type == other.type &&
|
25
|
-
@delim == other.delim
|
26
|
-
end
|
27
|
-
|
28
|
-
def is_literal?
|
29
|
-
[:literal_string, :literal_number].include? @type
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_s
|
33
|
-
res = ":#{@type || @token_type}: #{@val}"
|
34
|
-
res += " (#{@delim})" if delim
|
35
|
-
res
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
class SQL
|
40
|
-
attr_reader :atoms, :tokenizer
|
41
|
-
|
42
|
-
def initialize(db_type, db_infos)
|
43
|
-
klass = case db_type
|
44
|
-
when :mysql
|
45
|
-
MySQLTokenizer
|
46
|
-
when :sqlite
|
47
|
-
SQLiteTokenizer
|
48
|
-
else
|
49
|
-
Sqreen.log.warn format('warning: db_type %s not found, falling back to default SQL type', db_type)
|
50
|
-
SQLTokenizer
|
51
|
-
end
|
52
|
-
@tokenizer = klass.new(db_type, db_infos)
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_s
|
56
|
-
res = "Parsed: #{@req}\n"
|
57
|
-
nb = 0
|
58
|
-
@atoms.each do |atom|
|
59
|
-
res << "\t" + nb.to_s + ': ' + atom.to_s + "\n"
|
60
|
-
nb += 1
|
61
|
-
end
|
62
|
-
res
|
63
|
-
end
|
64
|
-
|
65
|
-
def parse(req)
|
66
|
-
@req = req
|
67
|
-
@atoms = []
|
68
|
-
@tokenizer.tokenize(req)
|
69
|
-
@tokenizer.each_token do |token, meta_type|
|
70
|
-
value = token[1]
|
71
|
-
type = token[0]
|
72
|
-
delim = case type
|
73
|
-
when :SINGLE_QUOTED_STRING
|
74
|
-
"'"
|
75
|
-
when :DOUBLE_QUOTED_STRING
|
76
|
-
'"'
|
77
|
-
end
|
78
|
-
atom = SQLAtom.new(value, meta_type, delim, type)
|
79
|
-
@atoms << atom
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def to_atoms(ary, type = :unknown)
|
84
|
-
ary.map { |frag| to_atom(frag, nil, type) }
|
85
|
-
end
|
86
|
-
|
87
|
-
def to_atom(_frag, _type = :unknown, _delim = nil)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
if $0 == __FILE__
|
94
|
-
s = Sqreen::Parsers::SQL.new :mysql, {}
|
95
|
-
s.parse(ARGV[0])
|
96
|
-
puts s
|
97
|
-
|
98
|
-
end
|