sql-maker 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +38 -0
- data/Rakefile +1 -1
- data/doc/README.md +1 -1
- data/lib/sql/maker.rb +12 -12
- data/lib/sql/maker/condition.rb +5 -6
- data/spec/maker/strict_spec.rb +26 -7
- data/sql-maker.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df6b66323d8c864915eacfa06aecea6273e58c46
|
4
|
+
data.tar.gz: 307efe4066f6b8ab303fe749ea80ae8022737325
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26c0a612e3bb5a35709ba269a2e775a10923cc0f628ff333d9226a2183947cc7bf034bd24b974271078150eb84fa18a6b29b9f48a4b194048d7628db1c0eac39
|
7
|
+
data.tar.gz: aadebe81d0678883500fc8dae3f2a66b7e799e7cebf23ef2a58f70e5f2be1de80dfb2cef5c850230f540c5d2a2fa3bd9bca4afc24762fa5d5e33667dbd3787dd
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -42,6 +42,44 @@ builder.add_select(sql_raw('COUNT(*)')).add_from('books').as_sql
|
|
42
42
|
|
43
43
|
Please see the [doc](./doc) directory.
|
44
44
|
|
45
|
+
## The JSON SQL Injection Vulnerability
|
46
|
+
|
47
|
+
Both perl and ruby verion of SQL::Maker has a JSON SQL Injection Vulnerability if not used in `strict` mode.
|
48
|
+
|
49
|
+
Therefore, I strongly recommend to use SQL::Maker in `strict` mode.
|
50
|
+
You can turn on the `strict` mode by passing `:strict => true` as:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
SQL::Maker.new(...., :strict => true)
|
54
|
+
SQL::Maker::Select.new(...., :strict => true)
|
55
|
+
```
|
56
|
+
|
57
|
+
In strict mode, array or hash conditions are not accepted anymore. A sample usage snippet is shown in below:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
require 'sql-maker'
|
61
|
+
include SQL::Maker::Helper # adds SQL::QueryMaker functions such as sql_le, etc
|
62
|
+
|
63
|
+
builder = SQL::Maker::Select.new(:strict => true)
|
64
|
+
|
65
|
+
builder.select('user', ['*'], {:name => json['name']})
|
66
|
+
#=> SELECT * FROM `user` WHERE `name` = ?
|
67
|
+
|
68
|
+
builder.select('user', ['*'], {:name => ['foo', 'bar']})
|
69
|
+
#=> SQL::Maker::Error! Will not generate SELECT * FROM `name` IN (?, ?) any more
|
70
|
+
|
71
|
+
builder.select('user', ['*'], {:name => sql_in(['foo', 'bar'])})
|
72
|
+
#=> SELECT * FROM `user` WHERE `name` IN (?, ?)
|
73
|
+
|
74
|
+
builder.select('fruit', ['*'], {:price => sql_le(json['max_price'])})
|
75
|
+
#=> SELECT * FROM `fruit` WHERE `price` <= ?
|
76
|
+
```
|
77
|
+
|
78
|
+
See following articles for more details (perl version)
|
79
|
+
|
80
|
+
* http://blog.kazuhooku.com/2014/07/the-json-sql-injection-vulnerability.html (English)
|
81
|
+
* http://developers.mobage.jp/blog/2014/7/3/jsonsql-injection (Japanese)
|
82
|
+
|
45
83
|
## ChangeLog
|
46
84
|
|
47
85
|
See [CHANGELOG.md](CHANGELOG.md) for details.
|
data/Rakefile
CHANGED
data/doc/README.md
CHANGED
data/lib/sql/maker.rb
CHANGED
@@ -84,11 +84,12 @@ class SQL::Maker
|
|
84
84
|
columns += [val.as_sql(nil, Proc.new {|e| self._quote(e) })]
|
85
85
|
bind_columns += val.bind
|
86
86
|
else
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
if val.is_a?(Array) && self.strict
|
88
|
+
croak("cannot pass in an unblessed ref as an argument in strict mode")
|
89
|
+
end
|
90
|
+
|
91
|
+
if val.is_a?(Array)
|
92
|
+
# builder.insert( :foo => { :created_on => ["NOW()"] })
|
92
93
|
# builder.insert( :foo => [ 'UNIX_TIMESTAMP(?)', '2011-04-12 00:34:12' ] )
|
93
94
|
stmt, sub_bind = [val.first, val[1..-1]]
|
94
95
|
columns += [stmt]
|
@@ -181,14 +182,13 @@ class SQL::Maker
|
|
181
182
|
columns += ["#{quoted_col} = " + val.as_sql(nil, Proc.new {|label| self._quote(label) })]
|
182
183
|
bind_columns += val.bind
|
183
184
|
else
|
184
|
-
if self.strict
|
185
|
+
if val.is_a?(Array) && self.strict
|
185
186
|
croak("cannot pass in an unblessed ref as an argument in strict mode")
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
# builder.update( :foo => \[ 'VALUES(foo) + ?', 10 ] )
|
187
|
+
end
|
188
|
+
|
189
|
+
if val.is_a?(Array)
|
190
|
+
# builder.update( :foo => [ 'NOW()' ] )
|
191
|
+
# builder.update( :foo => [ 'VALUES(foo) + ?', 10 ] )
|
192
192
|
stmt, sub_bind = [val.first, val[1..-1]]
|
193
193
|
columns += ["#{quoted_col} = " + stmt]
|
194
194
|
bind_columns += sub_bind
|
data/lib/sql/maker/condition.rb
CHANGED
@@ -44,7 +44,7 @@ class SQL::Maker::Condition
|
|
44
44
|
if val.is_a?(SQL::QueryMaker)
|
45
45
|
return [val.as_sql(col, self.method(:_quote)), val.bind]
|
46
46
|
elsif self.strict
|
47
|
-
croak("can pass only SQL::QueryMaker as an argument in strict mode")
|
47
|
+
croak("Condition#add: can pass only SQL::QueryMaker object as an argument in strict mode")
|
48
48
|
end
|
49
49
|
|
50
50
|
if val.is_a?(Array)
|
@@ -57,18 +57,17 @@ class SQL::Maker::Condition
|
|
57
57
|
end
|
58
58
|
elsif val.is_a?(Hash)
|
59
59
|
op, v = val.each.first
|
60
|
-
op = op.upcase
|
60
|
+
op = op.to_s.upcase
|
61
61
|
if ( op == 'AND' || op == 'OR' ) && v.is_a?(Array)
|
62
|
-
# {'foo'=>[{'>' => 'bar'},{'<' => 'baz'}]} => (`foo` > ?) OR (`foo` < ?)
|
62
|
+
# {'foo'=>{'or' => [{'>' => 'bar'},{'<' => 'baz'}]}} => (`foo` > ?) OR (`foo` < ?)
|
63
63
|
return self._make_or_term(col, op, v)
|
64
64
|
elsif ( op == 'IN' || op == 'NOT IN' )
|
65
|
+
# {'foo'=>{'in' => ['bar','baz']}} => `foo` IN (?, ?)
|
65
66
|
return self._make_in_term(col, op, v)
|
66
67
|
elsif ( op == 'BETWEEN' ) && v.is_a?(Array)
|
67
|
-
croak("USAGE:
|
68
|
+
croak("USAGE: add(foo => {BETWEEN => [a, b]})") if v.size != 2
|
68
69
|
return [self._quote(col) + " BETWEEN ? AND ?", v]
|
69
70
|
else
|
70
|
-
# make_term(foo => { '<' => \"DATE_SUB(NOW(), INTERVAL 3 DAY)"}) => 'foo < DATE_SUB(NOW(), INTERVAL 3 DAY)'
|
71
|
-
# return [self._quote(col) + " op " + v, []]
|
72
71
|
# make_term(foo => { '<' => 3 }) => foo < 3
|
73
72
|
return [self._quote(col) + " #{op} ?", [v]]
|
74
73
|
end
|
data/spec/maker/strict_spec.rb
CHANGED
@@ -2,6 +2,8 @@ require_relative '../spec_helper'
|
|
2
2
|
require 'sql/maker'
|
3
3
|
|
4
4
|
describe 'SQL::Maker' do
|
5
|
+
include SQL::Maker::Helper
|
6
|
+
|
5
7
|
let(:maker) do
|
6
8
|
SQL::Maker.new(
|
7
9
|
:driver => 'SQLite',
|
@@ -13,6 +15,7 @@ describe 'SQL::Maker' do
|
|
13
15
|
|
14
16
|
it "maker.new_condition" do
|
15
17
|
expect { maker.new_condition.add(:foo => [1]) }.to raise_error(SQL::Maker::Error)
|
18
|
+
expect { maker.new_condition.add(:foo => {'!=' => ''}) }.to raise_error(SQL::Maker::Error)
|
16
19
|
end
|
17
20
|
|
18
21
|
it "select.new_condition" do
|
@@ -25,21 +28,37 @@ describe 'SQL::Maker' do
|
|
25
28
|
expect { maker.select("user", ['*'], { :name => ["John", "Tom" ]}) }.to raise_error(SQL::Maker::Error)
|
26
29
|
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
context "maker.insert" do
|
32
|
+
it "raise error by strict mode" do
|
33
|
+
expect { maker.insert(
|
34
|
+
:user, { :name => "John", :created_on => ["datetime(now)"] }
|
35
|
+
) }.to raise_error(SQL::Maker::Error)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "using term" do
|
39
|
+
sql, binds = maker.insert(:user, { :name => "John", :created_on => sql_raw("datetime(now)") })
|
40
|
+
expect(sql).to be == %Q{INSERT INTO "user"\n("name", "created_on")\nVALUES (?, datetime(now))}
|
41
|
+
expect(binds.join(',')).to be == 'John'
|
42
|
+
end
|
32
43
|
end
|
33
44
|
|
34
45
|
it "maker.delete" do
|
35
46
|
expect { maker.delete(:user, { :name => ["John", "Tom"]}) }.to raise_error(SQL::Maker::Error)
|
36
47
|
end
|
37
48
|
|
38
|
-
|
39
|
-
|
49
|
+
context "maker.update where" do
|
50
|
+
it "raise error by strict mode" do
|
51
|
+
expect { maker.update(:user, {:name => "John"}, { :user_id => [1, 2] }) }.to raise_error(SQL::Maker::Error)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "using term" do
|
55
|
+
sql, binds = maker.update(:user, {:name => "John"}, { :user_id => sql_in([1, 2]) })
|
56
|
+
expect(sql).to be == %Q{UPDATE "user" SET "name" = ? WHERE ("user_id" IN (?,?))}
|
57
|
+
expect(binds.join(',')).to be == 'John,1,2'
|
58
|
+
end
|
40
59
|
end
|
41
60
|
|
42
61
|
it "maker.update set" do
|
43
|
-
expect { maker.update(:user, {:name => "select *"}) }.to raise_error(SQL::Maker::Error)
|
62
|
+
expect { sql, bind = maker.update(:user, {:name => ["select *"]}) }.to raise_error(SQL::Maker::Error)
|
44
63
|
end
|
45
64
|
end
|
data/sql-maker.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "sql-maker"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.4"
|
8
8
|
spec.authors = ["Naotoshi Seo"]
|
9
9
|
spec.email = ["sonots@gmail.com"]
|
10
10
|
spec.summary = %q{SQL Builder for Ruby}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sql-maker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naotoshi Seo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|