Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
c168fa03
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c168fa03
编写于
6月 06, 2019
作者:
R
Ryuta Kamizono
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Merge pull request #36420 from kamipo/quoted_identifier_regex
Allow quoted identifier string as safe SQL string
上级
60a6bcec
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
166 addition
and
68 deletion
+166
-68
activerecord/lib/active_record/attribute_methods.rb
activerecord/lib/active_record/attribute_methods.rb
+0
-53
activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
...lib/active_record/connection_adapters/abstract/quoting.rb
+37
-0
activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
...rd/lib/active_record/connection_adapters/mysql/quoting.rb
+26
-5
activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
...b/active_record/connection_adapters/postgresql/quoting.rb
+22
-0
activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
.../lib/active_record/connection_adapters/sqlite3/quoting.rb
+20
-0
activerecord/lib/active_record/relation/query_methods.rb
activerecord/lib/active_record/relation/query_methods.rb
+1
-1
activerecord/lib/active_record/sanitization.rb
activerecord/lib/active_record/sanitization.rb
+31
-2
activerecord/test/cases/associations/eager_test.rb
activerecord/test/cases/associations/eager_test.rb
+1
-1
activerecord/test/cases/relations_test.rb
activerecord/test/cases/relations_test.rb
+2
-2
activerecord/test/cases/unsafe_raw_sql_test.rb
activerecord/test/cases/unsafe_raw_sql_test.rb
+26
-4
未找到文件。
activerecord/lib/active_record/attribute_methods.rb
浏览文件 @
c168fa03
...
...
@@ -159,59 +159,6 @@ def attribute_names
end
end
# Regexp for column names (with or without a table name prefix). Matches
# the following:
# "#{table_name}.#{column_name}"
# "#{column_name}"
COLUMN_NAME
=
/\A(?:\w+\.)?\w+\z/i
# Regexp for column names with order (with or without a table name
# prefix, with or without various order modifiers). Matches the following:
# "#{table_name}.#{column_name}"
# "#{table_name}.#{column_name} #{direction}"
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
# "#{table_name}.#{column_name} NULLS LAST"
# "#{column_name}"
# "#{column_name} #{direction}"
# "#{column_name} #{direction} NULLS FIRST"
# "#{column_name} NULLS LAST"
COLUMN_NAME_WITH_ORDER
=
/
\A
(?:\w+\.)?
\w+
(?:\s+asc|\s+desc)?
(?:\s+nulls\s+(?:first|last))?
\z
/ix
def
disallow_raw_sql!
(
args
,
permit:
COLUMN_NAME
)
# :nodoc:
unexpected
=
nil
args
.
each
do
|
arg
|
next
if
arg
.
is_a?
(
Symbol
)
||
Arel
.
arel_node?
(
arg
)
||
arg
.
to_s
.
split
(
/\s*,\s*/
).
all?
{
|
part
|
permit
.
match?
(
part
)
}
(
unexpected
||=
[])
<<
arg
end
return
unless
unexpected
if
allow_unsafe_raw_sql
==
:deprecated
ActiveSupport
::
Deprecation
.
warn
(
"Dangerous query method (method whose arguments are used as raw "
\
"SQL) called with non-attribute argument(s): "
\
"
#{
unexpected
.
map
(
&
:inspect
).
join
(
", "
)
}
. Non-attribute "
\
"arguments will be disallowed in Rails 6.1. This method should "
\
"not be called with user-provided values, such as request "
\
"parameters or model attributes. Known-safe values can be passed "
\
"by wrapping them in Arel.sql()."
)
else
raise
(
ActiveRecord
::
UnknownAttributeReference
,
"Query method called with non-attribute argument(s): "
+
unexpected
.
map
(
&
:inspect
).
join
(
", "
)
)
end
end
# Returns true if the given attribute exists, otherwise false.
#
# class Person < ActiveRecord::Base
...
...
activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
浏览文件 @
c168fa03
...
...
@@ -142,6 +142,43 @@ def sanitize_as_sql_comment(value) # :nodoc:
value
.
to_s
.
gsub
(
%r{ (/ (?: |
\g
<1>)
\*
)
\+
?
\s
* |
\s
* (
\*
(?: |
\g
<2>) /) }x
,
""
)
end
def
column_name_matcher
# :nodoc:
COLUMN_NAME
end
def
column_name_with_order_matcher
# :nodoc:
COLUMN_NAME_WITH_ORDER
end
# Regexp for column names (with or without a table name prefix).
# Matches the following:
#
# "#{table_name}.#{column_name}"
# "#{column_name}"
COLUMN_NAME
=
/\A(?:\w+\.)?\w+\z/i
# Regexp for column names with order (with or without a table name prefix,
# with or without various order modifiers). Matches the following:
#
# "#{table_name}.#{column_name}"
# "#{table_name}.#{column_name} #{direction}"
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
# "#{table_name}.#{column_name} NULLS LAST"
# "#{column_name}"
# "#{column_name} #{direction}"
# "#{column_name} #{direction} NULLS FIRST"
# "#{column_name} NULLS LAST"
COLUMN_NAME_WITH_ORDER
=
/
\A
(?:\w+\.)?
\w+
(?:\s+ASC|\s+DESC)?
(?:\s+NULLS\s+(?:FIRST|LAST))?
\z
/ix
private_constant
:COLUMN_NAME
,
:COLUMN_NAME_WITH_ORDER
private
def
type_casted_binds
(
binds
)
if
binds
.
first
.
is_a?
(
Array
)
...
...
activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
浏览文件 @
c168fa03
...
...
@@ -32,12 +32,33 @@ def quoted_binary(value)
"x'
#{
value
.
hex
}
'"
end
def
_type_cast
(
value
)
case
value
when
Date
,
Time
then
value
else
super
end
def
column_name_matcher
COLUMN_NAME
end
def
column_name_with_order_matcher
COLUMN_NAME_WITH_ORDER
end
COLUMN_NAME
=
/\A(?:(`?)\w+\k<1>\.)?(`?)\w+\k<2>\z/i
COLUMN_NAME_WITH_ORDER
=
/
\A
(?:(`?)\w+\k<1>\.)?
(`?)\w+\k<2>
(?:\s+ASC|\s+DESC)?
\z
/ix
private_constant
:COLUMN_NAME
,
:COLUMN_NAME_WITH_ORDER
private
def
_type_cast
(
value
)
case
value
when
Date
,
Time
then
value
else
super
end
end
end
end
end
...
...
activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
浏览文件 @
c168fa03
...
...
@@ -78,6 +78,28 @@ def lookup_cast_type_from_column(column) # :nodoc:
type_map
.
lookup
(
column
.
oid
,
column
.
fmod
,
column
.
sql_type
)
end
def
column_name_matcher
COLUMN_NAME
end
def
column_name_with_order_matcher
COLUMN_NAME_WITH_ORDER
end
COLUMN_NAME
=
/\A(?:("?)\w+\k<1>\.)?("?)\w+\k<2>(?:::\w+)?\z/i
COLUMN_NAME_WITH_ORDER
=
/
\A
(?:("?)\w+\k<1>\.)?
("?)\w+\k<2>
(?:::\w+)?
(?:\s+ASC|\s+DESC)?
(?:\s+NULLS\s+(?:FIRST|LAST))?
\z
/ix
private_constant
:COLUMN_NAME
,
:COLUMN_NAME_WITH_ORDER
private
def
lookup_cast_type
(
sql_type
)
super
(
query_value
(
"SELECT
#{
quote
(
sql_type
)
}
::regtype::oid"
,
"SCHEMA"
).
to_i
)
...
...
activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
浏览文件 @
c168fa03
...
...
@@ -45,6 +45,26 @@ def unquoted_false
0
end
def
column_name_matcher
COLUMN_NAME
end
def
column_name_with_order_matcher
COLUMN_NAME_WITH_ORDER
end
COLUMN_NAME
=
/\A(?:("?)\w+\k<1>\.)?("?)\w+\k<2>\z/i
COLUMN_NAME_WITH_ORDER
=
/
\A
(?:("?)\w+\k<1>\.)?
("?)\w+\k<2>
(?:\s+ASC|\s+DESC)?
\z
/ix
private_constant
:COLUMN_NAME
,
:COLUMN_NAME_WITH_ORDER
private
def
_type_cast
(
value
)
...
...
activerecord/lib/active_record/relation/query_methods.rb
浏览文件 @
c168fa03
...
...
@@ -1254,7 +1254,7 @@ def preprocess_order_args(order_args)
@klass
.
disallow_raw_sql!
(
order_args
.
flat_map
{
|
a
|
a
.
is_a?
(
Hash
)
?
a
.
keys
:
a
},
permit:
AttributeMethods
::
ClassMethods
::
COLUMN_NAME_WITH_ORDER
permit:
connection
.
column_name_with_order_matcher
)
validate_order_args
(
order_args
)
...
...
activerecord/lib/active_record/sanitization.rb
浏览文件 @
c168fa03
...
...
@@ -61,8 +61,9 @@ def sanitize_sql_for_assignment(assignments, default_table_name = table_name)
# # => "id ASC"
def
sanitize_sql_for_order
(
condition
)
if
condition
.
is_a?
(
Array
)
&&
condition
.
first
.
to_s
.
include?
(
"?"
)
disallow_raw_sql!
([
condition
.
first
],
permit:
AttributeMethods
::
ClassMethods
::
COLUMN_NAME_WITH_ORDER
disallow_raw_sql!
(
[
condition
.
first
],
permit:
connection
.
column_name_with_order_matcher
)
# Ensure we aren't dealing with a subclass of String that might
...
...
@@ -133,6 +134,34 @@ def sanitize_sql_array(ary)
end
end
def
disallow_raw_sql!
(
args
,
permit:
connection
.
column_name_matcher
)
# :nodoc:
unexpected
=
nil
args
.
each
do
|
arg
|
next
if
arg
.
is_a?
(
Symbol
)
||
Arel
.
arel_node?
(
arg
)
||
arg
.
to_s
.
split
(
/\s*,\s*/
).
all?
{
|
part
|
permit
.
match?
(
part
)
}
(
unexpected
||=
[])
<<
arg
end
return
unless
unexpected
if
allow_unsafe_raw_sql
==
:deprecated
ActiveSupport
::
Deprecation
.
warn
(
"Dangerous query method (method whose arguments are used as raw "
\
"SQL) called with non-attribute argument(s): "
\
"
#{
unexpected
.
map
(
&
:inspect
).
join
(
", "
)
}
. Non-attribute "
\
"arguments will be disallowed in Rails 6.1. This method should "
\
"not be called with user-provided values, such as request "
\
"parameters or model attributes. Known-safe values can be passed "
\
"by wrapping them in Arel.sql()."
)
else
raise
(
ActiveRecord
::
UnknownAttributeReference
,
"Query method called with non-attribute argument(s): "
+
unexpected
.
map
(
&
:inspect
).
join
(
", "
)
)
end
end
private
def
replace_bind_variables
(
statement
,
values
)
raise_if_bind_arity_mismatch
(
statement
,
statement
.
count
(
"?"
),
values
.
size
)
...
...
activerecord/test/cases/associations/eager_test.rb
浏览文件 @
c168fa03
...
...
@@ -523,7 +523,7 @@ def test_eager_association_loading_with_belongs_to_and_order_string_with_unquote
def
test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name
quoted_posts_id
=
Comment
.
connection
.
quote_table_name
(
"posts"
)
+
"."
+
Comment
.
connection
.
quote_column_name
(
"id"
)
assert_nothing_raised
do
Comment
.
includes
(
:post
).
references
(
:posts
).
order
(
Arel
.
sql
(
quoted_posts_id
)
)
Comment
.
includes
(
:post
).
references
(
:posts
).
order
(
quoted_posts_id
)
end
end
...
...
activerecord/test/cases/relations_test.rb
浏览文件 @
c168fa03
...
...
@@ -1679,7 +1679,7 @@ def test_automatically_added_order_references
scope
=
Post
.
order
(
"comments.body"
)
assert_equal
[
"comments"
],
scope
.
references_values
scope
=
Post
.
order
(
Arel
.
sql
(
"
#{
Comment
.
quoted_table_name
}
.
#{
Comment
.
quoted_primary_key
}
"
)
)
scope
=
Post
.
order
(
"
#{
Comment
.
quoted_table_name
}
.
#{
Comment
.
quoted_primary_key
}
"
)
if
current_adapter?
(
:OracleAdapter
)
assert_equal
[
"COMMENTS"
],
scope
.
references_values
else
...
...
@@ -1704,7 +1704,7 @@ def test_automatically_added_reorder_references
scope
=
Post
.
reorder
(
"comments.body"
)
assert_equal
%w(comments)
,
scope
.
references_values
scope
=
Post
.
reorder
(
Arel
.
sql
(
"
#{
Comment
.
quoted_table_name
}
.
#{
Comment
.
quoted_primary_key
}
"
)
)
scope
=
Post
.
reorder
(
"
#{
Comment
.
quoted_table_name
}
.
#{
Comment
.
quoted_primary_key
}
"
)
if
current_adapter?
(
:OracleAdapter
)
assert_equal
[
"COMMENTS"
],
scope
.
references_values
else
...
...
activerecord/test/cases/unsafe_raw_sql_test.rb
浏览文件 @
c168fa03
...
...
@@ -77,7 +77,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal
ids_expected
,
ids_disabled
end
test
"order: allows table and column name"
do
test
"order: allows table and column name
s
"
do
ids_expected
=
Post
.
order
(
Arel
.
sql
(
"title"
)).
pluck
(
:id
)
ids_depr
=
with_unsafe_raw_sql_deprecated
{
Post
.
order
(
"posts.title"
).
pluck
(
:id
)
}
...
...
@@ -87,6 +87,17 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal
ids_expected
,
ids_disabled
end
test
"order: allows quoted table and column names"
do
ids_expected
=
Post
.
order
(
Arel
.
sql
(
"title"
)).
pluck
(
:id
)
quoted_title
=
Post
.
connection
.
quote_table_name
(
"posts.title"
)
ids_depr
=
with_unsafe_raw_sql_deprecated
{
Post
.
order
(
quoted_title
).
pluck
(
:id
)
}
ids_disabled
=
with_unsafe_raw_sql_disabled
{
Post
.
order
(
quoted_title
).
pluck
(
:id
)
}
assert_equal
ids_expected
,
ids_depr
assert_equal
ids_expected
,
ids_disabled
end
test
"order: allows column name and direction in string"
do
ids_expected
=
Post
.
order
(
Arel
.
sql
(
"title desc"
)).
pluck
(
:id
)
...
...
@@ -116,10 +127,10 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
[
"asc"
,
"desc"
,
""
].
each
do
|
direction
|
%w(first last)
.
each
do
|
position
|
ids_expected
=
Post
.
order
(
Arel
.
sql
(
"type
#{
direction
}
nulls
#{
position
}
"
)).
pluck
(
:id
)
ids_expected
=
Post
.
order
(
Arel
.
sql
(
"type
::text
#{
direction
}
nulls
#{
position
}
"
)).
pluck
(
:id
)
ids_depr
=
with_unsafe_raw_sql_deprecated
{
Post
.
order
(
"type
#{
direction
}
nulls
#{
position
}
"
).
pluck
(
:id
)
}
ids_disabled
=
with_unsafe_raw_sql_disabled
{
Post
.
order
(
"type
#{
direction
}
nulls
#{
position
}
"
).
pluck
(
:id
)
}
ids_depr
=
with_unsafe_raw_sql_deprecated
{
Post
.
order
(
"type
::text
#{
direction
}
nulls
#{
position
}
"
).
pluck
(
:id
)
}
ids_disabled
=
with_unsafe_raw_sql_disabled
{
Post
.
order
(
"type
::text
#{
direction
}
nulls
#{
position
}
"
).
pluck
(
:id
)
}
assert_equal
ids_expected
,
ids_depr
assert_equal
ids_expected
,
ids_disabled
...
...
@@ -262,6 +273,17 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal
titles_expected
,
titles_disabled
end
test
"pluck: allows quoted table and column names"
do
titles_expected
=
Post
.
pluck
(
Arel
.
sql
(
"title"
))
quoted_title
=
Post
.
connection
.
quote_table_name
(
"posts.title"
)
titles_depr
=
with_unsafe_raw_sql_deprecated
{
Post
.
pluck
(
quoted_title
)
}
titles_disabled
=
with_unsafe_raw_sql_disabled
{
Post
.
pluck
(
quoted_title
)
}
assert_equal
titles_expected
,
titles_depr
assert_equal
titles_expected
,
titles_disabled
end
test
"pluck: disallows invalid column name"
do
with_unsafe_raw_sql_disabled
do
assert_raises
(
ActiveRecord
::
UnknownAttributeReference
)
do
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录