sql-maker 0.0.3 → 0.0.4
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/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
|