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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32d150cb48d1dafd939ac1562fc6e7a31195172d
4
- data.tar.gz: 749f497d5f5a1f5d38a1f1855e575725b862bf9a
3
+ metadata.gz: df6b66323d8c864915eacfa06aecea6273e58c46
4
+ data.tar.gz: 307efe4066f6b8ab303fe749ea80ae8022737325
5
5
  SHA512:
6
- metadata.gz: a474871843140b6871e998e583bfe4222a89dc43db85f4a121379438eaf80bb648a36749166f91da4fffa69e8eff9d103f278a39860bf78960eb06e7916c2405
7
- data.tar.gz: 994cf90b1c734b301f7fb4c09bdedfe55a8c00bb5ec38530874be625c3f939d7f94c33cea071dae1b6062868d6e4dbcf21decd932978f86c10b8456e1ea517a3
6
+ metadata.gz: 26c0a612e3bb5a35709ba269a2e775a10923cc0f628ff333d9226a2183947cc7bf034bd24b974271078150eb84fa18a6b29b9f48a4b194048d7628db1c0eac39
7
+ data.tar.gz: aadebe81d0678883500fc8dae3f2a66b7e799e7cebf23ef2a58f70e5f2be1de80dfb2cef5c850230f540c5d2a2fa3bd9bca4afc24762fa5d5e33667dbd3787dd
@@ -1,3 +1,9 @@
1
+ ## 0.0.4 (2014/09/14)
2
+
3
+ Fixes:
4
+
5
+ * Fixed strict mode for insert/update (thanks to memememomo)
6
+
1
7
  ## 0.0.3 (2014/06/21)
2
8
 
3
9
  Fixes:
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
@@ -3,7 +3,7 @@ require "bundler/gem_tasks"
3
3
  require 'rspec/core'
4
4
  require 'rspec/core/rake_task'
5
5
  RSpec::Core::RakeTask.new(:spec) do |spec|
6
- spec.pattern = FileList['spec/**/*_spec.rb']
6
+ spec.pattern = 'spec/**{,/*/**}/*_spec.rb'
7
7
  end
8
8
  task :default => :spec
9
9
 
@@ -5,4 +5,4 @@
5
5
  * [sql/maker/condition.md](./sql/maker/condition.md)
6
6
  * [sql/maker/helper.md](./sql/maker/helper.md)
7
7
  * [sql/maker/select_set.md](./sql/maker/select_set.md)
8
- * [sql/queyr_maker.md](./sql/maker.md)
8
+ * [sql/query_maker.md](./sql/query_maker.md)
@@ -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
- croak("cannot pass in an unblessed ref as an argument in strict mode") if self.strict
88
- if val.is_a?(Hash)
89
- # builder.insert(:foo => { :created_on => ["NOW()"] })
90
- columns += [val]
91
- elsif val.is_a?(Array)
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
- if val.is_a?(Hash)
187
- # builder.update(:foo => { :created_on => \"NOW()" })
188
- # columns += ["quoted_col = " + $val
189
- end
190
- elsif val.is_a?(Array)
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
@@ -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.to_s
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: make_term(foo => {BETWEEN => [a, b]})") if v.size != 2
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
@@ -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
- it "maker.insert" do
29
- expect { maker.insert(
30
- :user, { :name => "John", :created_on => "datetime(now)" }
31
- ) }.to raise_error(SQL::Maker::Error)
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
- it "maker.update where" do
39
- expect { maker.update(:user, {:name => "John"}, { :user_id => [1, 2] }) }.to raise_error(SQL::Maker::Error)
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
@@ -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.3"
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.3
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-06-21 00:00:00.000000000 Z
11
+ date: 2014-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler