sinatra 2.0.0 → 2.0.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/AUTHORS.md +1 -0
- data/CHANGELOG.md +22 -2
- data/CONTRIBUTING.md +6 -0
- data/Gemfile +2 -1
- data/README.es.md +728 -347
- data/README.md +62 -49
- data/README.ru.md +546 -292
- data/README.zh.md +77 -15
- data/VERSION +1 -0
- data/lib/sinatra/base.rb +8 -6
- data/lib/sinatra/show_exceptions.rb +43 -11
- data/lib/sinatra/version.rb +1 -1
- data/sinatra.gemspec +2 -1
- metadata +8 -7
data/README.zh.md
CHANGED
@@ -239,6 +239,17 @@ end
|
|
239
239
|
```
|
240
240
|
顺便一提,除非你禁用了路径遍历攻击防护(见下文),请求路径可能在匹配路由前发生改变。
|
241
241
|
|
242
|
+
你也可以通过`:mustermann_opt`选项定义[Mustermann](https://github.com/sinatra/mustermann)来匹配路由。
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
get '\A/posts\z', :mustermann_opts => { :type => :regexp, :check_anchors => false } do
|
246
|
+
# matches /posts exactly, with explicit anchoring
|
247
|
+
"If you match an anchored pattern clap your hands!"
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
它看起来像一个[条件](https://github.com/sinatra/sinatra/blob/master/README.zh.md#%E6%9D%A1%E4%BB%B6),但实际不是!这些选项将被合并到全局的`mustermann_opts`。
|
252
|
+
|
242
253
|
### 条件
|
243
254
|
|
244
255
|
路由可以包含各种匹配条件,比如 user agent:
|
@@ -1302,33 +1313,59 @@ get '/:value' do
|
|
1302
1313
|
end
|
1303
1314
|
```
|
1304
1315
|
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1316
|
+
#### 会话加密
|
1317
|
+
|
1318
|
+
为提高安全性,cookie 中的会话数据使用`HMAC-SHA1`进行加密。会话加密的最佳实践应当是像`HMAC-SHA1`这样生成大于或等于64字节 (512 bits, 128 hex characters)的随机值。应当避免使用少于32字节(256 bits, 64 hex characters)的随机值。应当使用生成器来创建安全的密钥,而不是拍脑袋决定。
|
1319
|
+
|
1320
|
+
默认情况下,Sinatra会生成一个32字节的密钥,但随着应用程序的每次重新启动,它都会发生改变。如果有多个应用程序的实例,使用Sinatra生成密钥,每个实例将有不同的密钥,这可能不是您想要的。
|
1321
|
+
|
1322
|
+
为了更好的安全性和可用性,[建议](https://12factor.net/config)生成安全的随机密钥,并将其存储在运行应用程序的每个主机上的环境变量中,以便所有应用程序实例都将共享相同的密钥。并且应该定期更新会话密钥。下面是一些创建64比特密钥的例子:
|
1323
|
+
|
1324
|
+
#### 生成密钥
|
1309
1325
|
|
1310
1326
|
```ruby
|
1311
|
-
|
1327
|
+
$ ruby -e "require 'securerandom'; puts SecureRandom.hex(64)"
|
1328
|
+
99ae8af...snip...ec0f262ac
|
1329
|
+
```
|
1312
1330
|
|
1313
|
-
|
1314
|
-
"value = " << session['value'].inspect
|
1315
|
-
end
|
1331
|
+
#### 生成密钥(小贴士)
|
1316
1332
|
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1333
|
+
MRI Ruby目前认为[sysrandom gem](https://github.com/cryptosphere/sysrandom)使用系统的随机数生成器要比用户态的`OpenSSL`好。
|
1334
|
+
|
1335
|
+
```ruby
|
1336
|
+
$ gem install sysrandom
|
1337
|
+
Building native extensions. This could take a while...
|
1338
|
+
Successfully installed sysrandom-1.x
|
1339
|
+
1 gem installed
|
1340
|
+
|
1341
|
+
$ ruby -e "require 'sysrandom/securerandom'; puts SecureRandom.hex(64)"
|
1342
|
+
99ae8af...snip...ec0f262ac
|
1320
1343
|
```
|
1321
1344
|
|
1322
|
-
|
1323
|
-
然而,每次启动应用时,该密码都会变化,你也可以自己设置该密码,以便所有的应用实例共享:
|
1345
|
+
#### 从环境变量使用密钥
|
1324
1346
|
|
1347
|
+
将Sinatra的SESSION_SECRET环境变量设置为生成的值。在主机的重新启动之间保存这个值。由于这样做的方法会因系统而异,仅供说明之用:
|
1325
1348
|
```
|
1326
|
-
|
1349
|
+
# echo "export SESSION_SECRET=99ae8af...snip...ec0f262ac" >> ~/.bashrc
|
1327
1350
|
```
|
1328
1351
|
|
1329
|
-
|
1352
|
+
#### 应用的密钥配置
|
1330
1353
|
|
1354
|
+
如果SESSION SECRET环境变量不可用,将把应用的随机密钥设置为不安全的。
|
1355
|
+
|
1356
|
+
关于[sysrandom gem](https://github.com/cryptosphere/sysrandom)的更多用法:
|
1357
|
+
|
1358
|
+
```ruby
|
1359
|
+
require 'securerandom'
|
1360
|
+
# -or- require 'sysrandom/securerandom'
|
1361
|
+
set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) }
|
1331
1362
|
```
|
1363
|
+
|
1364
|
+
#### 会话配置
|
1365
|
+
|
1366
|
+
如果你想进一步配置会话,可以在设置 `sessions` 时提供一个选项 hash 作为第二个参数:
|
1367
|
+
|
1368
|
+
```ruby
|
1332
1369
|
set :sessions, :domain => 'foo.com'
|
1333
1370
|
```
|
1334
1371
|
|
@@ -1338,6 +1375,31 @@ set :sessions, :domain => 'foo.com'
|
|
1338
1375
|
set :sessions, :domain => '.foo.com'
|
1339
1376
|
```
|
1340
1377
|
|
1378
|
+
#### 选择你自己的会话中间件
|
1379
|
+
|
1380
|
+
请注意 `enable :sessions` 实际将所有的数据保存在一个 cookie 中。
|
1381
|
+
这可能并不总是你想要的(cookie 中存储大量的数据会增加你的流量)。
|
1382
|
+
你可以使用任何 Rack session 中间件:要达到此目的,**不要**使用 `enable :sessions`,
|
1383
|
+
而是按照自己的需要引入想使用的中间件:
|
1384
|
+
|
1385
|
+
```ruby
|
1386
|
+
enable :sessions
|
1387
|
+
set :session_store, Rack::Session::Pool
|
1388
|
+
```
|
1389
|
+
|
1390
|
+
另一种选择是不要调用enable:sessions,而是像你想要的其他中间件一样加入你的中间件。
|
1391
|
+
|
1392
|
+
重要的是要注意,使用此方法时,默认情况下不会启用基于会话的保护。
|
1393
|
+
|
1394
|
+
还需要添加Rack中间件:
|
1395
|
+
|
1396
|
+
```ruby
|
1397
|
+
use Rack::Session::Pool, :expire_after => 2592000
|
1398
|
+
use Rack::Protection::RemoteToken
|
1399
|
+
use Rack::Protection::SessionHijacking
|
1400
|
+
```
|
1401
|
+
更多[安全防护配置](https://github.com/sinatra/sinatra#configuring-attack-protection)的信息。
|
1402
|
+
|
1341
1403
|
### 中断请求
|
1342
1404
|
|
1343
1405
|
要想在过滤器或路由中立即中断一个请求:
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.1.rc1
|
data/lib/sinatra/base.rb
CHANGED
@@ -915,6 +915,7 @@ module Sinatra
|
|
915
915
|
|
916
916
|
def call!(env) # :nodoc:
|
917
917
|
@env = env
|
918
|
+
@params = IndifferentHash.new
|
918
919
|
@request = Request.new(env)
|
919
920
|
@response = Response.new
|
920
921
|
template_cache.clear if settings.reload_templates
|
@@ -1024,7 +1025,8 @@ module Sinatra
|
|
1024
1025
|
params.delete("ignore") # TODO: better params handling, maybe turn it into "smart" object or detect changes
|
1025
1026
|
original, @params = @params, @params.merge(params) if params.any?
|
1026
1027
|
|
1027
|
-
|
1028
|
+
regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? {|subpattern| subpattern.is_a?(Mustermann::Regular)} )
|
1029
|
+
if regexp_exists
|
1028
1030
|
captures = pattern.match(route).captures
|
1029
1031
|
values += captures
|
1030
1032
|
@params[:captures] = captures
|
@@ -1086,7 +1088,7 @@ module Sinatra
|
|
1086
1088
|
|
1087
1089
|
# Dispatch a request with error handling.
|
1088
1090
|
def dispatch!
|
1089
|
-
force_encoding(@params
|
1091
|
+
force_encoding(@params.merge!(@request.params))
|
1090
1092
|
|
1091
1093
|
invoke do
|
1092
1094
|
static! if settings.static? && (request.get? || request.head?)
|
@@ -1160,7 +1162,7 @@ module Sinatra
|
|
1160
1162
|
|
1161
1163
|
class << self
|
1162
1164
|
CALLERS_TO_IGNORE = [ # :nodoc:
|
1163
|
-
/\/sinatra(\/(base|main|show_exceptions))?\.rb$/,
|
1165
|
+
/\/sinatra(\/(base|main|show_exceptions))?\.rb$/, # all sinatra code
|
1164
1166
|
/lib\/tilt.*\.rb$/, # all tilt code
|
1165
1167
|
/^\(.*\)$/, # generated code
|
1166
1168
|
/rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
|
@@ -1434,7 +1436,7 @@ module Sinatra
|
|
1434
1436
|
return unless running?
|
1435
1437
|
# Use Thin's hard #stop! if available, otherwise just #stop.
|
1436
1438
|
running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
|
1437
|
-
$stderr.puts "== Sinatra has ended his set (crowd applauds)" unless
|
1439
|
+
$stderr.puts "== Sinatra has ended his set (crowd applauds)" unless suppress_messages?
|
1438
1440
|
set :running_server, nil
|
1439
1441
|
set :handler_name, nil
|
1440
1442
|
end
|
@@ -1520,7 +1522,7 @@ module Sinatra
|
|
1520
1522
|
prototype
|
1521
1523
|
# Run the instance we created:
|
1522
1524
|
handler.run(self, server_settings) do |server|
|
1523
|
-
unless
|
1525
|
+
unless suppress_messages?
|
1524
1526
|
$stderr.puts "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
|
1525
1527
|
end
|
1526
1528
|
|
@@ -1533,7 +1535,7 @@ module Sinatra
|
|
1533
1535
|
end
|
1534
1536
|
end
|
1535
1537
|
|
1536
|
-
def
|
1538
|
+
def suppress_messages?
|
1537
1539
|
handler_name =~ /cgi/i || quiet
|
1538
1540
|
end
|
1539
1541
|
|
@@ -25,28 +25,63 @@ module Sinatra
|
|
25
25
|
|
26
26
|
if prefers_plain_text?(env)
|
27
27
|
content_type = "text/plain"
|
28
|
-
|
28
|
+
body = dump_exception(e)
|
29
29
|
else
|
30
30
|
content_type = "text/html"
|
31
|
-
|
31
|
+
body = pretty(env, e)
|
32
32
|
end
|
33
33
|
|
34
34
|
env["rack.errors"] = errors
|
35
35
|
|
36
|
-
# Post 893a2c50 in rack/rack, the #pretty method above, implemented in
|
37
|
-
# Rack::ShowExceptions, returns a String instead of an array.
|
38
|
-
body = Array(exception)
|
39
|
-
|
40
36
|
[
|
41
37
|
500,
|
42
38
|
{
|
43
39
|
"Content-Type" => content_type,
|
44
|
-
"Content-Length" => body.
|
40
|
+
"Content-Length" => body.bytesize.to_s
|
45
41
|
},
|
46
|
-
body
|
42
|
+
[body]
|
47
43
|
]
|
48
44
|
end
|
49
45
|
|
46
|
+
# Pulled from Rack::ShowExceptions in order to override TEMPLATE.
|
47
|
+
# If Rack provides another way to override, this could be removed
|
48
|
+
# in the future.
|
49
|
+
def pretty(env, exception)
|
50
|
+
req = Rack::Request.new(env)
|
51
|
+
|
52
|
+
# This double assignment is to prevent an "unused variable" warning on
|
53
|
+
# Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
|
54
|
+
path = path = (req.script_name + req.path_info).squeeze("/")
|
55
|
+
|
56
|
+
# This double assignment is to prevent an "unused variable" warning on
|
57
|
+
# Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
|
58
|
+
frames = frames = exception.backtrace.map { |line|
|
59
|
+
frame = OpenStruct.new
|
60
|
+
if line =~ /(.*?):(\d+)(:in `(.*)')?/
|
61
|
+
frame.filename = $1
|
62
|
+
frame.lineno = $2.to_i
|
63
|
+
frame.function = $4
|
64
|
+
|
65
|
+
begin
|
66
|
+
lineno = frame.lineno-1
|
67
|
+
lines = ::File.readlines(frame.filename)
|
68
|
+
frame.pre_context_lineno = [lineno-CONTEXT, 0].max
|
69
|
+
frame.pre_context = lines[frame.pre_context_lineno...lineno]
|
70
|
+
frame.context_line = lines[lineno].chomp
|
71
|
+
frame.post_context_lineno = [lineno+CONTEXT, lines.size].min
|
72
|
+
frame.post_context = lines[lineno+1..frame.post_context_lineno]
|
73
|
+
rescue
|
74
|
+
end
|
75
|
+
|
76
|
+
frame
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
}.compact
|
81
|
+
|
82
|
+
TEMPLATE.result(binding)
|
83
|
+
end
|
84
|
+
|
50
85
|
private
|
51
86
|
|
52
87
|
def bad_request?(e)
|
@@ -360,6 +395,3 @@ enabled the <code>show_exceptions</code> setting.</p>
|
|
360
395
|
HTML
|
361
396
|
end
|
362
397
|
end
|
363
|
-
|
364
|
-
Rack::ShowExceptions.send :remove_const, "TEMPLATE"
|
365
|
-
Rack::ShowExceptions.const_set "TEMPLATE", Sinatra::ShowExceptions::TEMPLATE
|
data/lib/sinatra/version.rb
CHANGED
data/sinatra.gemspec
CHANGED
@@ -17,7 +17,8 @@ Gem::Specification.new 'sinatra', version do |s|
|
|
17
17
|
"MAINTENANCE.md",
|
18
18
|
"Rakefile",
|
19
19
|
"SECURITY.md",
|
20
|
-
"sinatra.gemspec"
|
20
|
+
"sinatra.gemspec",
|
21
|
+
"VERSION"]
|
21
22
|
s.test_files = s.files.select { |p| p =~ /^test\/.*_test.rb/ }
|
22
23
|
s.extra_rdoc_files = s.files.select { |p| p =~ /^README/ } << 'LICENSE'
|
23
24
|
s.rdoc_options = %w[--line-numbers --inline-source --title Sinatra --main README.rdoc --encoding=UTF-8]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Mizerany
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2018-02-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rack
|
@@ -47,14 +47,14 @@ dependencies:
|
|
47
47
|
requirements:
|
48
48
|
- - '='
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: 2.0.
|
50
|
+
version: 2.0.1.rc1
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - '='
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 2.0.
|
57
|
+
version: 2.0.1.rc1
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: mustermann
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +108,7 @@ files:
|
|
108
108
|
- README.zh.md
|
109
109
|
- Rakefile
|
110
110
|
- SECURITY.md
|
111
|
+
- VERSION
|
111
112
|
- examples/chat.rb
|
112
113
|
- examples/simple.rb
|
113
114
|
- examples/stream.ru
|
@@ -142,12 +143,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
143
|
version: 2.2.0
|
143
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
145
|
requirements:
|
145
|
-
- - "
|
146
|
+
- - ">"
|
146
147
|
- !ruby/object:Gem::Version
|
147
|
-
version:
|
148
|
+
version: 1.3.1
|
148
149
|
requirements: []
|
149
150
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.6.
|
151
|
+
rubygems_version: 2.6.8
|
151
152
|
signing_key:
|
152
153
|
specification_version: 4
|
153
154
|
summary: Classy web-development dressed in a DSL
|