padrino-core 0.12.1 → 0.12.2
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/lib/padrino-core/application/application_setup.rb +9 -0
- data/lib/padrino-core/application/params_protection.rb +129 -0
- data/lib/padrino-core/application/routing.rb +34 -7
- data/lib/padrino-core/application.rb +2 -0
- data/lib/padrino-core/logger.rb +9 -12
- data/lib/padrino-core/reloader/storage.rb +3 -3
- data/lib/padrino-core/reloader.rb +15 -0
- data/lib/padrino-core/router.rb +5 -1
- data/lib/padrino-core/server.rb +2 -0
- data/lib/padrino-core/version.rb +1 -1
- data/test/fixtures/apps/helpers/support.rb +1 -0
- data/test/test_application.rb +30 -0
- data/test/test_csrf_protection.rb +22 -1
- data/test/test_logger.rb +6 -6
- data/test/test_params_protection.rb +159 -0
- data/test/test_reloader_simple.rb +2 -2
- data/test/test_router.rb +16 -0
- data/test/test_routing.rb +30 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dec1c7a3513869018c0576596a7888261759d25c
|
4
|
+
data.tar.gz: 6ba616394f122fc4bf166facc114554cbddf2331
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6507e1e6ae0a0d2ca472e740928b548d7d9340d5d046725c8c049ece42e595db33018b1f551c148c846a1618e5cc2dd583bca65d202b49e8e86aa669eb770c85
|
7
|
+
data.tar.gz: bc2666c168ba2678e3045db54803ddcec24fd9c486a8b77e03e01c7eb0a01785ed15ac95c487955723f5b7ed864cbd5939a67d4252a5aff5a622ba3c1ba760e0
|
@@ -151,6 +151,15 @@ module Padrino
|
|
151
151
|
I18n.reload!
|
152
152
|
end
|
153
153
|
|
154
|
+
# allow custome session management
|
155
|
+
def setup_sessions(builder)
|
156
|
+
if sessions.kind_of?(Hash) && sessions[:use]
|
157
|
+
builder.use sessions[:use], sessions[:config] || {}
|
158
|
+
else
|
159
|
+
super
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
154
163
|
# sets up csrf protection for the app
|
155
164
|
def setup_csrf_protection(builder)
|
156
165
|
check_csrf_protection_dependency
|
@@ -0,0 +1,129 @@
|
|
1
|
+
begin
|
2
|
+
require 'active_support/core_ext/object/deep_dup' # AS 4.1
|
3
|
+
rescue LoadError => ex
|
4
|
+
require 'active_support/core_ext/hash/deep_dup' # AS >= 3.1
|
5
|
+
end
|
6
|
+
|
7
|
+
module Padrino
|
8
|
+
##
|
9
|
+
# Padrino application module providing means for mass-assignment protection.
|
10
|
+
#
|
11
|
+
module ParamsProtection
|
12
|
+
class << self
|
13
|
+
def registered(app)
|
14
|
+
included(app)
|
15
|
+
end
|
16
|
+
|
17
|
+
def included(base)
|
18
|
+
base.send(:include, InstanceMethods)
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
##
|
25
|
+
# Implements filtering of url query params. Can prevent mass-assignment.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# post :update, :params => [:name, :email]
|
29
|
+
# post :update, :params => [:name, :id => Integer]
|
30
|
+
# post :update, :params => [:name => proc{ |v| v.reverse }]
|
31
|
+
# post :update, :params => [:name, :parent => [:name, :position]]
|
32
|
+
# post :update, :params => false
|
33
|
+
# post :update, :params => true
|
34
|
+
# @example
|
35
|
+
# params :name, :email, :password => prox{ |v| v.reverse }
|
36
|
+
# post :update
|
37
|
+
# @example
|
38
|
+
# App.controller :accounts, :params => [:name, :position] do
|
39
|
+
# post :create
|
40
|
+
# post :update, :with => [ :id ], :params => [:name, :position, :addition]
|
41
|
+
# get :show, :with => :id, :params => false
|
42
|
+
# get :search, :params => true
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
def params(*allowed_params)
|
46
|
+
allowed_params = prepare_allowed_params(allowed_params)
|
47
|
+
condition do
|
48
|
+
@original_params = params.deep_dup
|
49
|
+
filter_params!(params, allowed_params)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def prepare_allowed_params(allowed_params)
|
56
|
+
param_filter = {}
|
57
|
+
allowed_params.each do |key,value|
|
58
|
+
case
|
59
|
+
when key.kind_of?(Hash) && !value
|
60
|
+
param_filter.update(prepare_allowed_params(key))
|
61
|
+
when value.kind_of?(Hash) || value.kind_of?(Array)
|
62
|
+
param_filter[key.to_s] = prepare_allowed_params(value)
|
63
|
+
else
|
64
|
+
param_filter[key.to_s] = value == false ? false : (value || true)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
param_filter.freeze
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module InstanceMethods
|
72
|
+
##
|
73
|
+
# Filters a hash of parameters leaving only allowed ones and possibly
|
74
|
+
# typecasting and processing the others.
|
75
|
+
#
|
76
|
+
# @param [Hash] params
|
77
|
+
# Parameters to filter.
|
78
|
+
# Warning: this hash will be changed by deleting or replacing its values.
|
79
|
+
# @param [Hash] allowed_params
|
80
|
+
# A hash of allowed keys and value classes or processing procs. Supported
|
81
|
+
# scalar classes are: Integer (empty string is cast to nil).
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# filter_params!( { "a" => "1", "b" => "abc", "d" => "drop" },
|
85
|
+
# { "a" => Integer, "b" => true } )
|
86
|
+
# # => { "a" => 1, "b" => "abc" }
|
87
|
+
# filter_params!( { "id" => "", "child" => { "name" => "manny" } },
|
88
|
+
# { "id" => Integer, "child" => { "name" => proc{ |v| v.camelize } } } )
|
89
|
+
# # => { "id" => nil, "child" => { "name" => "Manny" } }
|
90
|
+
# filter_params!( { "a" => ["1", "2", "3"] },
|
91
|
+
# { "a" => true } )
|
92
|
+
# # => { "a" => ["1", "2", "3"] }
|
93
|
+
# filter_params!( { "persons" => {"p-1" => { "name" => "manny", "age" => "50" }, "p-2" => { "name" => "richard", "age" => "50" } } },
|
94
|
+
# { "persons" => { "name" => true } } )
|
95
|
+
# # => { "persons" => {"p-1" => { "name" => "manny" }, "p-2" => { "name" => "richard" } } }
|
96
|
+
#
|
97
|
+
def filter_params!(params, allowed_params)
|
98
|
+
params.each do |key,value|
|
99
|
+
type = allowed_params[key]
|
100
|
+
next if value.kind_of?(Array) && type
|
101
|
+
case
|
102
|
+
when type.kind_of?(Hash)
|
103
|
+
if key == key.pluralize
|
104
|
+
value.each do |array_index,array_value|
|
105
|
+
value[array_index] = filter_params!(array_value, type)
|
106
|
+
end
|
107
|
+
else
|
108
|
+
params[key] = filter_params!(value, type)
|
109
|
+
end
|
110
|
+
when type == Integer
|
111
|
+
params[key] = value.empty? ? nil : value.to_i
|
112
|
+
when type.kind_of?(Proc)
|
113
|
+
params[key] = type.call(value)
|
114
|
+
when type == true
|
115
|
+
else
|
116
|
+
params.delete(key)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Returns the original unfiltered query parameters hash.
|
123
|
+
#
|
124
|
+
def original_params
|
125
|
+
@original_params || params
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -132,6 +132,19 @@ class HttpRouter
|
|
132
132
|
@routes.sort!{ |a, b| a.order <=> b.order }
|
133
133
|
end
|
134
134
|
|
135
|
+
class Node::Glob
|
136
|
+
def to_code
|
137
|
+
id = root.next_counter
|
138
|
+
"request.params << (globbed_params#{id} = [])
|
139
|
+
until request.path.empty?
|
140
|
+
globbed_params#{id} << request.path.shift
|
141
|
+
#{super}
|
142
|
+
end
|
143
|
+
request.path[0,0] = globbed_params#{id}
|
144
|
+
request.params.pop"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
135
148
|
class Node::SpanningRegex
|
136
149
|
def to_code
|
137
150
|
params_count = @ordered_indicies.size
|
@@ -386,6 +399,7 @@ module Padrino
|
|
386
399
|
@_conditions, original_conditions = options.delete(:conditions), @_conditions
|
387
400
|
@_defaults, original_defaults = options, @_defaults
|
388
401
|
@_accepts, original_accepts = options.delete(:accepts), @_accepts
|
402
|
+
@_params, original_params = options.delete(:params), @_params
|
389
403
|
|
390
404
|
# Application defaults.
|
391
405
|
@filters, original_filters = { :before => @filters[:before].dup, :after => @filters[:after].dup }, @filters
|
@@ -401,6 +415,7 @@ module Padrino
|
|
401
415
|
@_controller, @_parents, @_cache = original_controller, original_parent, original_cache
|
402
416
|
@_defaults, @_provides, @_map = original_defaults, original_provides, original_map
|
403
417
|
@_conditions, @_use_format, @_accepts = original_conditions, original_use_format, original_accepts
|
418
|
+
@_params = original_params
|
404
419
|
else
|
405
420
|
include(*args) if extensions.any?
|
406
421
|
end
|
@@ -582,28 +597,32 @@ module Padrino
|
|
582
597
|
##
|
583
598
|
# Instance method for url generation.
|
584
599
|
#
|
600
|
+
# @option options [String] :fragment
|
601
|
+
# An addition to url to identify a portion of requested resource (i.e #something).
|
602
|
+
# @option options [String] :anchor
|
603
|
+
# Synonym for fragment.
|
604
|
+
#
|
585
605
|
# @example
|
586
606
|
# url(:show, :id => 1)
|
587
607
|
# url(:show, :name => 'test', :id => 24)
|
588
608
|
# url(:show, 1)
|
589
609
|
# url(:controller_name, :show, :id => 21)
|
590
610
|
# url(:controller_show, :id => 29)
|
611
|
+
# url(:index, :fragment => 'comments')
|
591
612
|
#
|
592
613
|
def url(*args)
|
593
|
-
params = args.extract_options!
|
614
|
+
params = args.extract_options!
|
594
615
|
names, params_array = args.partition{|a| a.is_a?(Symbol)}
|
595
616
|
name = names[0, 2].join(" ").to_sym # route name is concatenated with underscores
|
596
|
-
|
597
|
-
|
598
|
-
params = value_to_param(params.symbolize_keys)
|
599
|
-
end
|
617
|
+
fragment = params.delete(:fragment) || params.delete(:anchor)
|
618
|
+
params = value_to_param(params.symbolize_keys)
|
600
619
|
url =
|
601
620
|
if params_array.empty?
|
602
621
|
compiled_router.path(name, params)
|
603
622
|
else
|
604
623
|
compiled_router.path(name, *(params_array << params))
|
605
624
|
end
|
606
|
-
rebase_url(url)
|
625
|
+
rebase_url(fragment ? url + '#' + fragment : url)
|
607
626
|
rescue HttpRouter::InvalidRouteException
|
608
627
|
route_error = "route mapping for url(#{name.inspect}) could not be found!"
|
609
628
|
raise Padrino::Routing::UnrecognizedException.new(route_error)
|
@@ -621,8 +640,8 @@ module Padrino
|
|
621
640
|
def rebase_url(url)
|
622
641
|
if url.start_with?('/')
|
623
642
|
new_url = ''
|
624
|
-
new_url << conform_uri(uri_root) if defined?(uri_root)
|
625
643
|
new_url << conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
|
644
|
+
new_url << conform_uri(uri_root) if defined?(uri_root)
|
626
645
|
new_url << url
|
627
646
|
else
|
628
647
|
url.blank? ? '/' : url
|
@@ -693,6 +712,7 @@ module Padrino
|
|
693
712
|
route_options = options.dup
|
694
713
|
route_options[:provides] = @_provides if @_provides
|
695
714
|
route_options[:accepts] = @_accepts if @_accepts
|
715
|
+
route_options[:params] = @_params unless @_params.nil? || route_options.include?(:params)
|
696
716
|
|
697
717
|
# Add Sinatra condition to check rack-protection failure.
|
698
718
|
if protect_from_csrf && (report_csrf_failure || allow_disabled_csrf)
|
@@ -767,6 +787,13 @@ module Padrino
|
|
767
787
|
def parse_route(path, options, verb)
|
768
788
|
route_options = {}
|
769
789
|
|
790
|
+
if options[:params] == true
|
791
|
+
options.delete(:params)
|
792
|
+
elsif options.include?(:params)
|
793
|
+
options[:params] ||= []
|
794
|
+
options[:params] += options[:with] if options[:with]
|
795
|
+
end
|
796
|
+
|
770
797
|
# We need check if path is a symbol, if that it's a named route.
|
771
798
|
map = options.delete(:map)
|
772
799
|
|
@@ -3,6 +3,7 @@ require 'padrino-core/application/routing'
|
|
3
3
|
require 'padrino-core/application/show_exceptions'
|
4
4
|
require 'padrino-core/application/authenticity_token'
|
5
5
|
require 'padrino-core/application/application_setup'
|
6
|
+
require 'padrino-core/application/params_protection'
|
6
7
|
|
7
8
|
module Padrino
|
8
9
|
##
|
@@ -14,6 +15,7 @@ module Padrino
|
|
14
15
|
class Application < Sinatra::Base
|
15
16
|
register Padrino::ApplicationSetup
|
16
17
|
register Padrino::Routing
|
18
|
+
register Padrino::ParamsProtection
|
17
19
|
|
18
20
|
##
|
19
21
|
# Returns the logger for this application.
|
data/lib/padrino-core/logger.rb
CHANGED
@@ -101,7 +101,7 @@ module Padrino
|
|
101
101
|
duration = Time.now - began_at
|
102
102
|
color = :red if duration > 1
|
103
103
|
action = colorize(action.to_s.upcase.rjust(@_pad), color)
|
104
|
-
duration = colorize('%0.4fs' % duration, :bold
|
104
|
+
duration = colorize('%0.4fs' % duration, color, :bold)
|
105
105
|
push "#{action} (#{duration}) #{message}", level
|
106
106
|
end
|
107
107
|
|
@@ -203,11 +203,11 @@ module Padrino
|
|
203
203
|
# Colors for levels
|
204
204
|
ColoredLevels = {
|
205
205
|
:fatal => [:bold, :red],
|
206
|
-
:error => [:red],
|
207
|
-
:warn => [:yellow],
|
208
|
-
:info => [:green],
|
209
|
-
:debug => [:cyan],
|
210
|
-
:devel => [:magenta]
|
206
|
+
:error => [:default, :red],
|
207
|
+
:warn => [:default, :yellow],
|
208
|
+
:info => [:default, :green],
|
209
|
+
:debug => [:default, :cyan],
|
210
|
+
:devel => [:default, :magenta]
|
211
211
|
} unless defined?(ColoredLevels)
|
212
212
|
|
213
213
|
##
|
@@ -218,14 +218,11 @@ module Padrino
|
|
218
218
|
# @see Padrino::Logging::ColorizedLogger::ColoredLevels
|
219
219
|
#
|
220
220
|
def colorize(string, *colors)
|
221
|
-
|
222
|
-
string = string.colorize(c)
|
223
|
-
end
|
224
|
-
string
|
221
|
+
string.colorize(:color => colors[0], :mode => colors[1])
|
225
222
|
end
|
226
223
|
|
227
224
|
def stylized_level(level)
|
228
|
-
style = ColoredLevels[level].map
|
225
|
+
style = "\e[%d;%dm" % ColoredLevels[level].map{|color| String::Colorizer.modes[color] || String::Colorizer.colors[color] }
|
229
226
|
[style, super, "\e[0m"] * ''
|
230
227
|
end
|
231
228
|
end
|
@@ -437,7 +434,7 @@ module Padrino
|
|
437
434
|
env["PATH_INFO"],
|
438
435
|
env["QUERY_STRING"].empty? ? "" : "?" + env["QUERY_STRING"],
|
439
436
|
' - ',
|
440
|
-
logger.colorize(status.to_s[0..3], :bold),
|
437
|
+
logger.colorize(status.to_s[0..3], :default, :bold),
|
441
438
|
' ',
|
442
439
|
code_to_name(status)
|
443
440
|
] * '',
|
@@ -6,7 +6,7 @@ module Padrino
|
|
6
6
|
def clear!
|
7
7
|
files.each_key do |file|
|
8
8
|
remove(file)
|
9
|
-
|
9
|
+
Reloader.remove_feature(file)
|
10
10
|
end
|
11
11
|
@files = {}
|
12
12
|
end
|
@@ -14,7 +14,7 @@ module Padrino
|
|
14
14
|
def remove(name)
|
15
15
|
file = files[name] || return
|
16
16
|
file[:constants].each{ |constant| Reloader.remove_constant(constant) }
|
17
|
-
file[:features].each{ |feature|
|
17
|
+
file[:features].each{ |feature| Reloader.remove_feature(feature) }
|
18
18
|
files.delete(name)
|
19
19
|
end
|
20
20
|
|
@@ -27,7 +27,7 @@ module Padrino
|
|
27
27
|
}
|
28
28
|
features = file && file[:features] || []
|
29
29
|
features.each{ |feature| Reloader.safe_load(feature, :force => true) }
|
30
|
-
|
30
|
+
Reloader.remove_feature(name) if old_features.include?(name)
|
31
31
|
end
|
32
32
|
|
33
33
|
def commit(name)
|
@@ -87,6 +87,7 @@ module Padrino
|
|
87
87
|
began_at = Time.now
|
88
88
|
file = figure_path(file)
|
89
89
|
return unless options[:force] || file_changed?(file)
|
90
|
+
return require(file) if external_feature?(file)
|
90
91
|
|
91
92
|
Storage.prepare(file) # might call #safe_load recursively
|
92
93
|
logger.devel(file_new?(file) ? :loading : :reload, began_at, file)
|
@@ -116,6 +117,13 @@ module Padrino
|
|
116
117
|
rescue NameError
|
117
118
|
end
|
118
119
|
|
120
|
+
##
|
121
|
+
# Remove a feature from $LOADED_FEATURES so it can be required again.
|
122
|
+
#
|
123
|
+
def remove_feature(file)
|
124
|
+
$LOADED_FEATURES.delete(file) unless external_feature?(file)
|
125
|
+
end
|
126
|
+
|
119
127
|
##
|
120
128
|
# Returns the list of special tracked files for Reloader.
|
121
129
|
#
|
@@ -229,6 +237,13 @@ module Padrino
|
|
229
237
|
files + special_files
|
230
238
|
end
|
231
239
|
|
240
|
+
##
|
241
|
+
# Tells if a feature is internal or external for Padrino project.
|
242
|
+
#
|
243
|
+
def external_feature?(file)
|
244
|
+
!file.start_with?(Padrino.root)
|
245
|
+
end
|
246
|
+
|
232
247
|
def constant_excluded?(const)
|
233
248
|
(exclude_constants - include_constants).any?{ |c| const._orig_klass_name.start_with?(c) }
|
234
249
|
end
|
data/lib/padrino-core/router.rb
CHANGED
@@ -79,13 +79,17 @@ module Padrino
|
|
79
79
|
|
80
80
|
rest = "/" if rest.empty?
|
81
81
|
|
82
|
-
|
82
|
+
env['SCRIPT_NAME'] = script_name + path
|
83
|
+
env['PATH_INFO'] = rest
|
84
|
+
last_result = app.call(env)
|
83
85
|
|
84
86
|
cascade_setting = app.respond_to?(:cascade) ? app.cascade : true
|
85
87
|
cascade_statuses = cascade_setting.respond_to?(:include?) ? cascade_setting : Mounter::DEFAULT_CASCADE
|
86
88
|
break unless cascade_setting && cascade_statuses.include?(last_result[0])
|
87
89
|
end
|
88
90
|
last_result || begin
|
91
|
+
env['SCRIPT_NAME'] = script_name
|
92
|
+
env['PATH_INFO'] = path_info
|
89
93
|
Padrino::Logger::Rack.new(nil,'/').send(:log, env, 404, {}, began_at) if logger.debug?
|
90
94
|
[404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path_info}"]]
|
91
95
|
end
|
data/lib/padrino-core/server.rb
CHANGED
@@ -44,6 +44,8 @@ module Padrino
|
|
44
44
|
options.update(detect_address(options))
|
45
45
|
options[:pid] = prepare_pid(options[:pid]) if options[:daemonize]
|
46
46
|
options[:server] = detect_rack_handler if options[:server].blank?
|
47
|
+
# disable Webrick AccessLog
|
48
|
+
options[:AccessLog] = []
|
47
49
|
new(options, app).start
|
48
50
|
end
|
49
51
|
|
data/lib/padrino-core/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_support/logger_silence'
|
data/test/test_application.rb
CHANGED
@@ -65,6 +65,36 @@ describe "Application" do
|
|
65
65
|
assert_equal 'shared', body
|
66
66
|
end
|
67
67
|
|
68
|
+
it 'should able to set custome session management' do
|
69
|
+
class PadrinoTestApp3 < Padrino::Application
|
70
|
+
set :sessions, :use => Rack::Session::Pool
|
71
|
+
end
|
72
|
+
Padrino.mount("PadrinoTestApp3").to("/")
|
73
|
+
PadrinoTestApp3.get('/write') { session[:foo] = "pool" }
|
74
|
+
PadrinoTestApp3.get('/read') { session[:foo] }
|
75
|
+
@app = Padrino.application
|
76
|
+
get '/write'
|
77
|
+
get '/read'
|
78
|
+
assert_equal 'pool', body
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should have different session values in different session management' do
|
82
|
+
class PadrinoTestApp3 < Padrino::Application
|
83
|
+
enable :sessions
|
84
|
+
end
|
85
|
+
class PadrinoTestApp4 < Padrino::Application
|
86
|
+
set :sessions, :use => Rack::Session::Pool
|
87
|
+
end
|
88
|
+
Padrino.mount("PadrinoTestApp3").to("/write")
|
89
|
+
Padrino.mount("PadrinoTestApp4").to("/read")
|
90
|
+
PadrinoTestApp3.get('/') { session[:foo] = "cookie" }
|
91
|
+
PadrinoTestApp4.get('/') { session[:foo] }
|
92
|
+
@app = Padrino.application
|
93
|
+
get '/write'
|
94
|
+
get '/read'
|
95
|
+
assert_equal '', body
|
96
|
+
end
|
97
|
+
|
68
98
|
# compare to: test_routing: allow global provides
|
69
99
|
it 'should set content_type to nil if none can be determined' do
|
70
100
|
mock_app do
|
@@ -27,6 +27,17 @@ describe "Application" do
|
|
27
27
|
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
|
28
28
|
assert_equal 403, status
|
29
29
|
end
|
30
|
+
|
31
|
+
it 'should allow requests with correct X-CSRF-TOKEN' do
|
32
|
+
post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a"
|
33
|
+
assert_equal 200, status
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should not allow requests with incorrect X-CSRF-TOKEN' do
|
37
|
+
post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b"
|
38
|
+
assert_equal 403, status
|
39
|
+
end
|
40
|
+
|
30
41
|
end
|
31
42
|
|
32
43
|
describe "without CSRF protection on" do
|
@@ -45,13 +56,23 @@ describe "Application" do
|
|
45
56
|
|
46
57
|
it 'should allow requests with correct tokens' do
|
47
58
|
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
|
48
|
-
assert_equal 200, status
|
59
|
+
assert_equal 200, status
|
49
60
|
end
|
50
61
|
|
51
62
|
it 'should allow requests with incorrect tokens' do
|
52
63
|
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
|
53
64
|
assert_equal 200, status
|
54
65
|
end
|
66
|
+
|
67
|
+
it 'should allow requests with correct X-CSRF-TOKEN' do
|
68
|
+
post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a"
|
69
|
+
assert_equal 200, status
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should allow requests with incorrect X-CSRF-TOKEN' do
|
73
|
+
post "/", {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b"
|
74
|
+
assert_equal 200, status
|
75
|
+
end
|
55
76
|
end
|
56
77
|
|
57
78
|
describe "with optional CSRF protection" do
|
data/test/test_logger.rb
CHANGED
@@ -71,7 +71,7 @@ describe "PadrinoLogger" do
|
|
71
71
|
get("/"){ "Foo" }
|
72
72
|
end
|
73
73
|
get "/"
|
74
|
-
assert_match /\e\[
|
74
|
+
assert_match /\e\[1;9m200\e\[0m OK/, Padrino.logger.log.string
|
75
75
|
end
|
76
76
|
|
77
77
|
describe "static asset logging" do
|
@@ -110,11 +110,11 @@ describe "PadrinoLogger" do
|
|
110
110
|
it 'should output under debug level' do
|
111
111
|
Padrino.logger.instance_eval{ @level = Padrino::Logger::Levels[:debug] }
|
112
112
|
access_to_mock_app
|
113
|
-
assert_match /\e\[36m DEBUG\e\[0m/, Padrino.logger.log.string
|
113
|
+
assert_match /\e\[0;36m DEBUG\e\[0m/, Padrino.logger.log.string
|
114
114
|
|
115
115
|
Padrino.logger.instance_eval{ @level = Padrino::Logger::Levels[:devel] }
|
116
116
|
access_to_mock_app
|
117
|
-
assert_match /\e\[36m DEBUG\e\[0m/, Padrino.logger.log.string
|
117
|
+
assert_match /\e\[0;36m DEBUG\e\[0m/, Padrino.logger.log.string
|
118
118
|
end
|
119
119
|
it 'should not output over debug level' do
|
120
120
|
Padrino.logger.instance_eval{ @level = Padrino::Logger::Levels[:info] }
|
@@ -164,7 +164,7 @@ describe "alternate logger" do
|
|
164
164
|
end
|
165
165
|
get "/"
|
166
166
|
|
167
|
-
assert_match /\e\[
|
167
|
+
assert_match /\e\[1;9m200\e\[0m OK/, @log.string
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
@@ -190,7 +190,7 @@ describe "alternate logger: stdlib logger" do
|
|
190
190
|
end
|
191
191
|
get "/"
|
192
192
|
|
193
|
-
assert_match /\e\[
|
193
|
+
assert_match /\e\[1;9m200\e\[0m OK/, @log.string
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
@@ -207,7 +207,7 @@ describe "options :colorize_logging" do
|
|
207
207
|
Padrino::Logger.setup!
|
208
208
|
|
209
209
|
access_to_mock_app
|
210
|
-
assert_match /\e\[
|
210
|
+
assert_match /\e\[1;9m200\e\[0m OK/, Padrino.logger.log.string
|
211
211
|
end
|
212
212
|
end
|
213
213
|
describe 'set value is false' do
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
2
|
+
require 'active_support/core_ext/hash/conversions'
|
3
|
+
|
4
|
+
describe "Padrino::ParamsProtection" do
|
5
|
+
before do
|
6
|
+
@teri = { 'name' => 'Teri Bauer', 'position' => 'baby' }
|
7
|
+
@kim = { 'name' => 'Kim Bauer', 'position' => 'daughter', 'child' => @teri }
|
8
|
+
@jack = { 'name' => 'Jack Bauer', 'position' => 'terrorist', 'child' => @kim }
|
9
|
+
@family = { 'name' => 'Bauer', 'persons' => { 1 => @teri, 2 => @kim, 3 => @jack } }
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should drop all parameters except allowed ones' do
|
13
|
+
result = nil
|
14
|
+
mock_app do
|
15
|
+
post :basic, :params => [ :name ] do
|
16
|
+
result = params
|
17
|
+
''
|
18
|
+
end
|
19
|
+
end
|
20
|
+
post '/basic?' + @jack.to_query
|
21
|
+
assert_equal({ 'name' => @jack['name'] }, result)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should preserve original params' do
|
25
|
+
result = nil
|
26
|
+
mock_app do
|
27
|
+
post :basic, :params => [ :name ] do
|
28
|
+
result = original_params
|
29
|
+
''
|
30
|
+
end
|
31
|
+
end
|
32
|
+
post '/basic?' + @jack.to_query
|
33
|
+
assert_equal(@jack, result)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should work with recursive data' do
|
37
|
+
result = nil
|
38
|
+
mock_app do
|
39
|
+
post :basic, :params => [ :name, :child => [ :name, :child => [ :name ] ] ] do
|
40
|
+
result = [params, original_params]
|
41
|
+
''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
post '/basic?' + @jack.to_query
|
45
|
+
assert_equal(
|
46
|
+
[
|
47
|
+
{ 'name' => @jack['name'], 'child' => { 'name' => @kim['name'], 'child' => { 'name' => @teri['name'] } } },
|
48
|
+
@jack
|
49
|
+
],
|
50
|
+
result
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should be able to process the data' do
|
55
|
+
result = nil
|
56
|
+
mock_app do
|
57
|
+
post :basic, :params => [ :name, :position => proc{ |v| 'anti-'+v } ] do
|
58
|
+
result = params
|
59
|
+
''
|
60
|
+
end
|
61
|
+
end
|
62
|
+
post '/basic?' + @jack.to_query
|
63
|
+
assert_equal({ 'name' => @jack['name'], 'position' => 'anti-terrorist' }, result)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should pass :with parameters' do
|
67
|
+
result = nil
|
68
|
+
mock_app do
|
69
|
+
post :basic, :with => [:id, :tag], :params => [ :name ] do
|
70
|
+
result = params
|
71
|
+
''
|
72
|
+
end
|
73
|
+
end
|
74
|
+
post '/basic/24/42?' + @jack.to_query
|
75
|
+
assert_equal({ 'name' => @jack['name'], 'id' => '24', 'tag' => '42' }, result)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should understand true or false values' do
|
79
|
+
result = nil
|
80
|
+
mock_app do
|
81
|
+
get :hide, :with => [ :id ], :params => false do
|
82
|
+
result = params
|
83
|
+
''
|
84
|
+
end
|
85
|
+
get :show, :with => [ :id ], :params => true do
|
86
|
+
result = params
|
87
|
+
''
|
88
|
+
end
|
89
|
+
end
|
90
|
+
get '/hide/1?' + @jack.to_query
|
91
|
+
assert_equal({"id"=>"1"}, result)
|
92
|
+
get '/show/1?' + @jack.to_query
|
93
|
+
assert_equal({"id"=>"1"}.merge(@jack), result)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should be configurable with controller options' do
|
97
|
+
result = nil
|
98
|
+
mock_app do
|
99
|
+
controller :persons, :params => [ :name ] do
|
100
|
+
post :create, :params => [ :name, :position ] do
|
101
|
+
result = params
|
102
|
+
''
|
103
|
+
end
|
104
|
+
post :update, :with => [ :id ] do
|
105
|
+
result = params
|
106
|
+
''
|
107
|
+
end
|
108
|
+
post :delete, :params => true do
|
109
|
+
result = params
|
110
|
+
''
|
111
|
+
end
|
112
|
+
post :destroy, :with => [ :id ], :params => false do
|
113
|
+
result = params
|
114
|
+
''
|
115
|
+
end
|
116
|
+
end
|
117
|
+
controller :noparam, :params => false do
|
118
|
+
get :index do
|
119
|
+
result = params
|
120
|
+
''
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
post '/persons/create?' + @jack.to_query
|
125
|
+
assert_equal({ 'name' => @jack['name'], 'position' => 'terrorist' }, result)
|
126
|
+
post '/persons/update/1?name=Chloe+O\'Brian&position=hacker'
|
127
|
+
assert_equal({ 'id' => '1', 'name' => 'Chloe O\'Brian' }, result)
|
128
|
+
post '/persons/delete?' + @jack.to_query
|
129
|
+
assert_equal(@jack, result)
|
130
|
+
post '/persons/destroy/1?' + @jack.to_query
|
131
|
+
assert_equal({"id"=>"1"}, result)
|
132
|
+
get '/noparam?a=1;b=2'
|
133
|
+
assert_equal({}, result)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should successfully filter hashes' do
|
137
|
+
result = nil
|
138
|
+
mock_app do
|
139
|
+
post :family, :params => [ :persons => [ :name ] ] do
|
140
|
+
result = params
|
141
|
+
''
|
142
|
+
end
|
143
|
+
end
|
144
|
+
post '/family?' + @family.to_query
|
145
|
+
assert_equal({"persons" => {"3" => {"name" => @jack["name"]}, "2" => {"name" => @kim["name"]}, "1" => {"name" => @teri["name"]}}}, result)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should pass arrays' do
|
149
|
+
result = nil
|
150
|
+
mock_app do
|
151
|
+
post :family, :params => [ :names => [] ] do
|
152
|
+
result = params
|
153
|
+
''
|
154
|
+
end
|
155
|
+
end
|
156
|
+
post '/family?names[]=Jack&names[]=Kim&names[]=Teri'
|
157
|
+
assert_equal({"names" => %w[Jack Kim Teri]}, result)
|
158
|
+
end
|
159
|
+
end
|
@@ -84,7 +84,7 @@ describe "SimpleReloader" do
|
|
84
84
|
assert_equal 2, @app.filters[:after].size # app + content-type + padrino-flash
|
85
85
|
assert_equal 0, @app.middleware.size
|
86
86
|
assert_equal 4, @app.routes.size # GET+HEAD of "/" + GET+HEAD of "/rand" = 4
|
87
|
-
assert_equal
|
87
|
+
assert_equal 4, @app.extensions.size # [Padrino::ApplicationSetup, Padrino::ParamsProtection, Padrino::Routing, Padrino::Flash]
|
88
88
|
assert_equal 0, @app.templates.size
|
89
89
|
@app.reload!
|
90
90
|
get "/rand"
|
@@ -94,7 +94,7 @@ describe "SimpleReloader" do
|
|
94
94
|
assert_equal 2, @app.filters[:after].size
|
95
95
|
assert_equal 0, @app.middleware.size
|
96
96
|
assert_equal 4, @app.routes.size # GET+HEAD of "/" = 2
|
97
|
-
assert_equal
|
97
|
+
assert_equal 4, @app.extensions.size # [Padrino::ApplicationSetup, Padrino::ParamsProtection, Padrino::Routing, Padrino::Flash]
|
98
98
|
assert_equal 0, @app.templates.size
|
99
99
|
end
|
100
100
|
end
|
data/test/test_router.rb
CHANGED
@@ -262,4 +262,20 @@ describe "Router" do
|
|
262
262
|
res = Rack::MockRequest.new(Padrino.application).get("/foo/", "HTTP_HOST" => "bar.padrino.org")
|
263
263
|
assert res.ok?
|
264
264
|
end
|
265
|
+
|
266
|
+
it 'should keep the same environment object' do
|
267
|
+
app = lambda { |env|
|
268
|
+
env['path'] = env['PATH_INFO']
|
269
|
+
[200, {'Content-Type' => 'text/plain'}, [""]]
|
270
|
+
}
|
271
|
+
map = Padrino::Router.new(
|
272
|
+
{ :path => '/bar', :to => app },
|
273
|
+
{ :path => '/foo/bar', :to => app },
|
274
|
+
{ :path => '/foo', :to => app }
|
275
|
+
)
|
276
|
+
|
277
|
+
env = Rack::MockRequest.env_for("/bar/foo")
|
278
|
+
map.call(env)
|
279
|
+
assert_equal "/foo", env["path"]
|
280
|
+
end
|
265
281
|
end
|
data/test/test_routing.rb
CHANGED
@@ -7,6 +7,7 @@ class FooError < RuntimeError; end
|
|
7
7
|
describe "Routing" do
|
8
8
|
before do
|
9
9
|
Padrino.clear!
|
10
|
+
ENV['RACK_BASE_URI'] = nil
|
10
11
|
end
|
11
12
|
|
12
13
|
it 'should serve static files with simple cache control' do
|
@@ -215,6 +216,8 @@ describe "Routing" do
|
|
215
216
|
get(:foo, :with => :id){ |id| "/foo/#{id}" }
|
216
217
|
get([:foo, :id]){ |id| "/foo/#{id}" }
|
217
218
|
get(:hash, :with => :id){ url(:hash, :id => 1) }
|
219
|
+
get(:anchor) { url(:anchor, :anchor => 'comments') }
|
220
|
+
get(:fragment) { url(:anchor, :fragment => 'comments') }
|
218
221
|
get([:hash, :id]){ url(:hash, :id => 1) }
|
219
222
|
get(:array, :with => :id){ url(:array, 23) }
|
220
223
|
get([:array, :id]){ url(:array, 23) }
|
@@ -232,6 +235,10 @@ describe "Routing" do
|
|
232
235
|
assert_equal "/foo/123", body
|
233
236
|
get "/hash/2"
|
234
237
|
assert_equal "/hash/1", body
|
238
|
+
get "/anchor"
|
239
|
+
assert_equal "/anchor#comments", body
|
240
|
+
get "/fragment"
|
241
|
+
assert_equal "/anchor#comments", body
|
235
242
|
get "/array/23"
|
236
243
|
assert_equal "/array/23", body
|
237
244
|
get "/hash_with_extra/1"
|
@@ -858,6 +865,18 @@ describe "Routing" do
|
|
858
865
|
ENV['RACK_BASE_URI'] = nil
|
859
866
|
end
|
860
867
|
|
868
|
+
it 'should use uri_root and RACK_BASE_URI' do
|
869
|
+
mock_app do
|
870
|
+
controller :foo do
|
871
|
+
get(:bar){ "bar" }
|
872
|
+
end
|
873
|
+
end
|
874
|
+
ENV['RACK_BASE_URI'] = '/base'
|
875
|
+
@app.uri_root = 'testing'
|
876
|
+
assert_equal '/base/testing/foo/bar', @app.url(:foo, :bar)
|
877
|
+
ENV['RACK_BASE_URI'] = nil
|
878
|
+
end
|
879
|
+
|
861
880
|
it 'should reset routes' do
|
862
881
|
mock_app do
|
863
882
|
get("/"){ "foo" }
|
@@ -898,6 +917,17 @@ describe "Routing" do
|
|
898
917
|
assert_equal "hello", body
|
899
918
|
end
|
900
919
|
|
920
|
+
it 'should set the params correctly even if using prioritized routes' do
|
921
|
+
mock_app do
|
922
|
+
get("*__sinatra__/:image.png"){}
|
923
|
+
get "/:primary/:secondary", :priority => :low do
|
924
|
+
"#{params[:primary]} #{params[:secondary]}"
|
925
|
+
end
|
926
|
+
end
|
927
|
+
get "/abc/def"
|
928
|
+
assert_equal "abc def", body
|
929
|
+
end
|
930
|
+
|
901
931
|
it 'should catch all after controllers' do
|
902
932
|
mock_app do
|
903
933
|
get(:index, :with => :slug, :priority => :low) { "catch all" }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: padrino-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Padrino Team
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2014-
|
14
|
+
date: 2014-05-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: padrino-support
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - '='
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.12.
|
22
|
+
version: 0.12.2
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.12.
|
29
|
+
version: 0.12.2
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: sinatra
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- lib/padrino-core/application/application_setup.rb
|
118
118
|
- lib/padrino-core/application/authenticity_token.rb
|
119
119
|
- lib/padrino-core/application/flash.rb
|
120
|
+
- lib/padrino-core/application/params_protection.rb
|
120
121
|
- lib/padrino-core/application/routing.rb
|
121
122
|
- lib/padrino-core/application/show_exceptions.rb
|
122
123
|
- lib/padrino-core/caller.rb
|
@@ -148,6 +149,7 @@ files:
|
|
148
149
|
- test/fixtures/apps/complex.rb
|
149
150
|
- test/fixtures/apps/demo_app.rb
|
150
151
|
- test/fixtures/apps/demo_demo.rb
|
152
|
+
- test/fixtures/apps/helpers/support.rb
|
151
153
|
- test/fixtures/apps/helpers/system_helpers.rb
|
152
154
|
- test/fixtures/apps/kiq.rb
|
153
155
|
- test/fixtures/apps/lib/myklass.rb
|
@@ -174,6 +176,7 @@ files:
|
|
174
176
|
- test/test_locale.rb
|
175
177
|
- test/test_logger.rb
|
176
178
|
- test/test_mounter.rb
|
179
|
+
- test/test_params_protection.rb
|
177
180
|
- test/test_reloader_complex.rb
|
178
181
|
- test/test_reloader_simple.rb
|
179
182
|
- test/test_reloader_system.rb
|
@@ -214,6 +217,7 @@ test_files:
|
|
214
217
|
- test/fixtures/apps/complex.rb
|
215
218
|
- test/fixtures/apps/demo_app.rb
|
216
219
|
- test/fixtures/apps/demo_demo.rb
|
220
|
+
- test/fixtures/apps/helpers/support.rb
|
217
221
|
- test/fixtures/apps/helpers/system_helpers.rb
|
218
222
|
- test/fixtures/apps/kiq.rb
|
219
223
|
- test/fixtures/apps/lib/myklass.rb
|
@@ -240,6 +244,7 @@ test_files:
|
|
240
244
|
- test/test_locale.rb
|
241
245
|
- test/test_logger.rb
|
242
246
|
- test/test_mounter.rb
|
247
|
+
- test/test_params_protection.rb
|
243
248
|
- test/test_reloader_complex.rb
|
244
249
|
- test/test_reloader_simple.rb
|
245
250
|
- test/test_reloader_system.rb
|