rad_ext 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rake_ext'
2
+
3
+ project(
4
+ name: "rad_ext",
5
+ gem: true,
6
+ summary: "Extensions for Rad Framework",
7
+
8
+ bin: 'bin',
9
+
10
+ author: "Alexey Petrushin",
11
+ homepage: "http://github.com/alexeypetrushin/rad_ext"
12
+ )
@@ -0,0 +1,22 @@
1
+ class Abstract
2
+ def initialize dir
3
+ @dir = File.expand_path(dir)
4
+ end
5
+
6
+ # def config options = {}
7
+ # rad.config.merge_config! "#{dir}/config/config.yml", options
8
+ # end
9
+
10
+ def routes
11
+ routes_file = "#{dir}/config/routes.rb"
12
+ load routes_file if File.exist? routes_file
13
+ end
14
+
15
+ def locales
16
+ I18n.load_path += Dir["#{dir}/config/locales/**/*.{rb,yml}"]
17
+ I18n.load_path += Dir["#{dir}/config/locales/*.{rb,yml}"]
18
+ end
19
+
20
+ protected
21
+ attr_reader :dir #, :after_config, :after_environment
22
+ end
@@ -0,0 +1,2 @@
1
+ class Runtime < Abstract
2
+ end
@@ -0,0 +1,32 @@
1
+ class Web < Abstract
2
+ def asset_paths *relative_paths
3
+ relative_paths = relative_paths.first if relative_paths.first.is_a? Array
4
+ relative_paths.each do |relative_path|
5
+ path = "#{dir}/#{relative_path}"
6
+ rad.assets.paths << path unless rad.assets.paths.include? path
7
+ end
8
+ end
9
+
10
+ def load_paths *relative_paths
11
+ relative_paths = relative_paths.first if relative_paths.first.is_a? Array
12
+ relative_paths.each do |relative_path|
13
+ path = "#{dir}/#{relative_path}"
14
+ $LOAD_PATH << path unless $LOAD_PATH.include? path
15
+ end
16
+ end
17
+
18
+ def template_paths *relative_paths
19
+ rad.template
20
+
21
+ relative_paths = relative_paths.first if relative_paths.first.is_a? Array
22
+ relative_paths.each do |relative_path|
23
+ path = "#{dir}/#{relative_path}"
24
+ rad.template.paths << path unless rad.template.paths.include? path
25
+ end
26
+ end
27
+
28
+ def autoload_paths *relative_paths
29
+ relative_paths = relative_paths.first if relative_paths.first.is_a? Array
30
+ relative_paths.each{|d| autoload_dir "#{dir}/#{d}", true}
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module ForgeryProtector
2
+ BROWSER_GENERATED_TYPES = %w(
3
+ text/html
4
+ text/plain
5
+ application/x-www-form-urlencoded
6
+ multipart/form-data
7
+ ).to_set
8
+
9
+ BROWSER_GENERATED_FORMATS = %w(html js)
10
+
11
+ protected
12
+ def protect_from_forgery
13
+ request = workspace.request
14
+ if request.session
15
+ sat = request.session['authenticity_token']
16
+ content_type = request.content_type
17
+ format = workspace.params.format
18
+
19
+ allow = (
20
+ request.get? or
21
+ (content_type.present? and !BROWSER_GENERATED_TYPES.include?(content_type.downcase)) or
22
+ (format.present? and !BROWSER_GENERATED_FORMATS.include?(format)) or
23
+ (sat.present? and sat == params.authenticity_token)
24
+ )
25
+
26
+ raise "invalid authenticity token!" unless allow
27
+
28
+ @authenticity_token = sat
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ # Sets format for :js as :html and wraps body into <textarea>
2
+ # Forms with files can be submitted by ajax only via iframe, and it requires
3
+ # the response have 'html' encoding and be wrapped into <textarea>
4
+ class AjaxHelper < Conveyors::Processor
5
+ def call
6
+ response = workspace.response.must_be.defined
7
+ request = workspace.request.must_be.defined
8
+
9
+ next_processor.call
10
+
11
+ if workspace.params? and workspace.params.format == 'js' and !request.xhr?
12
+ response.content_type = Mime['html']
13
+ workspace.content = "<textarea>#{workspace.content}</textarea>"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # enshure domain has no www. except if there's custom subdomain
2
+ class EnsureNoWww < Conveyors::Processor
3
+ def call
4
+ workspace.params.must_be.defined
5
+ if workspace.params.format == 'html' and url_with_www?
6
+ redirect_without_www
7
+ else
8
+ next_processor.call
9
+ end
10
+ end
11
+
12
+ protected
13
+ def uri
14
+ @uri ||= Uri.parse workspace.request.url
15
+ end
16
+
17
+ def url_with_www?
18
+ uri.host =~ /^www\./
19
+ end
20
+
21
+ def redirect_without_www
22
+ uri.host = uri.host.sub(/^www\./, '')
23
+ url = uri.to_s
24
+
25
+ response = workspace.response
26
+ response.status = 301
27
+ response.headers['Location'] = url
28
+ response.body = %(<html><body>You are being <a href="#{url.html_escape}">redirected</a>.</body></html>)
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ # %w(
2
+ # abstract
3
+ # runtime
4
+ # web
5
+ # ).each{|f| require "rad_ext/configurators/#{f}"}
6
+
7
+ class Micon::Core
8
+ def configure configurator_name, dir, &block
9
+ configurator_class = "Rad::Configurators::#{configurator_name.to_s.classify}".constantize
10
+ configurator = configurator_class.new dir
11
+ block.call configurator if block
12
+ end
13
+ end
@@ -0,0 +1,62 @@
1
+ # {
2
+ # :'ru' => {
3
+ # pluralize: lambda { |n|
4
+ # # Правило плюрализации для русского языка, взято из CLDR, http://unicode.org/cldr/
5
+ # #
6
+ # #
7
+ # # Russian language pluralization rules, taken from CLDR project, http://unicode.org/cldr/
8
+ # #
9
+ # # one -> n mod 10 is 1 and n mod 100 is not 11;
10
+ # # few -> n mod 10 in 2..4 and n mod 100 not in 12..14;
11
+ # # many -> n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14;
12
+ # # other -> everything else
13
+ # #
14
+ # # Пример
15
+ # #
16
+ # # :one = 1, 21, 31, 41, 51, 61...
17
+ # # :few = 2-4, 22-24, 32-34...
18
+ # # :many = 0, 5-20, 25-30, 35-40...
19
+ # # :other = 1.31, 2.31, 5.31...
20
+ # modulo10 = n.modulo(10)
21
+ # modulo100 = n.modulo(100)
22
+ #
23
+ # if modulo10 == 1 && modulo100 != 11
24
+ # :one
25
+ # elsif (modulo10 == 2 || modulo10 == 3 || modulo10 == 4) && !(modulo100 == 12 || modulo100 == 13 || modulo100 == 14)
26
+ # :few
27
+ # elsif modulo10 == 0 || (modulo10 == 5 || modulo10 == 6 || modulo10 == 7 || modulo10 == 8 || modulo10 == 9) || (modulo100 == 11 || modulo100 == 12 || modulo100 == 13 || modulo100 == 14)
28
+ # :many
29
+ # else
30
+ # :other
31
+ # end
32
+ # }
33
+ # }
34
+ # }
35
+
36
+ {
37
+ ru: {
38
+ i18n: {
39
+ plural: {
40
+ rule: lambda{|n|
41
+ # Правило плюрализации для русского языка, взято из CLDR, http://unicode.org/cldr/
42
+ #
43
+ #
44
+ # Russian language pluralization rules, taken from CLDR project, http://unicode.org/cldr/
45
+ #
46
+ # one -> n mod 10 is 1 and n mod 100 is not 11;
47
+ # few -> n mod 10 in 2..4 and n mod 100 not in 12..14;
48
+ # many -> n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14;
49
+ # other -> everything else
50
+ #
51
+ # Пример
52
+ #
53
+ # :one = 1, 21, 31, 41, 51, 61...
54
+ # :few = 2-4, 22-24, 32-34...
55
+ # :many = 0, 5-20, 25-30, 35-40...
56
+ # :other = 1.31, 2.31, 5.31...
57
+ n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,16 @@
1
+ # Hack, ActiveSupport currently uses differrent version
2
+ # gem 'i18n', '>= 0.4.1'
3
+ # require 'i18n'
4
+
5
+ require "i18n/backend/pluralization"
6
+ I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
7
+
8
+ I18n.load_path += Dir["#{__FILE__.dirname}/i18n/locales/*/*.{rb,yml}"]
9
+
10
+
11
+ #
12
+ # Helpers for Rad
13
+ #
14
+ [Rad::Controller::Abstract, Rad::Controller::Context].each do |klass|
15
+ klass.delegate :t, to: I18n
16
+ end
@@ -0,0 +1,16 @@
1
+ Rad::Controller::Abstract::ClassMethods.class_eval do
2
+ def prepare_model aclass, opt = {}
3
+ opt = opt.symbolize_keys
4
+ id = opt.delete(:id) || :id
5
+ variable = opt.delete(:variable) || aclass.alias.underscore
6
+
7
+ finder = opt.delete(:finder) || :find!
8
+
9
+ method = "prepare_#{variable}"
10
+ define_method method do
11
+ model = aclass.send finder, params[id]
12
+ instance_variable_set "@#{variable}", model
13
+ end
14
+ before method, opt
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ class UserError < StandardError
2
+ end
3
+
4
+ Object.class_eval do
5
+ def raise_user_error msg
6
+ raise UserError, msg
7
+ end
8
+
9
+ def self.raise_user_error msg
10
+ raise UserError, msg
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'rad'
2
+
3
+ %w(
4
+ i18n
5
+ prepare_model
6
+ user_error
7
+ ).each{|f| require "rad_ext/extensions/#{f}"}
@@ -0,0 +1,7 @@
1
+ gem 'i18n', '0.5.0'
2
+
3
+
4
+ if respond_to? :fake_gem
5
+ fake_gem 'rad_core'
6
+ fake_gem 'rad_assets'
7
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # Router
3
+ #
4
+ rad.router.routers = [
5
+ [:alias_router, Rad::Router::AliasRouter.new],
6
+ [:basic_router, Rad::Router::BasicRouter.new],
7
+ [:restful_router, Rad::Router::RestfulRouter.new],
8
+ [:object_router, Rad::Router::ObjectRouter.new]
9
+ ]
10
+
11
+
12
+ #
13
+ # Conveyors
14
+ #
15
+ rad.conveyors.web do |web|
16
+ # conveyor
17
+ web.use Rad::Conveyors::Processors::ConveyorLogger
18
+
19
+ # http
20
+ web.use Rad::Http::Processors::HttpWriter
21
+ web.use Rad::Http::Processors::PrepareParams
22
+ web.use Rad::Http::Processors::EvaluateFormat
23
+ web.use Rad::Http::Processors::HttpLogger
24
+
25
+ # forgery protection
26
+ web.use Rad::Processors::PrepareAutenticityToken
27
+
28
+ # ensure no www
29
+ web.use Rad::Processors::EnsureNoWww
30
+
31
+ # ajax
32
+ web.use Rad::Processors::AjaxHelper
33
+
34
+ # html
35
+ # web.use ScopedParams
36
+ web.use Rad::Html::Processors::PrepareFlash
37
+
38
+ # controller
39
+ web.use Rad::Controller::Processors::ControllerErrorHandling
40
+
41
+ # router
42
+ web.use Rad::Router::Processors::Router, :class, :method_name
43
+
44
+ # controller
45
+ web.use Rad::Controller::Processors::ControllerLogger
46
+ web.use Rad::Controller::Processors::ControllerCaller
47
+
48
+ web.build!
49
+ end
50
+
51
+
52
+ #
53
+ # RackAdapter
54
+ #
55
+ rad.http.initialize_rack do |builder|
56
+ # CommonLogger, ShowExceptions, Lint
57
+ builder.use Rack::Lint if rad.development?
58
+
59
+ # Static Files
60
+ if rad.http.static? and rad.http.public_path and rad.development?
61
+ filters = /^\/.*?\/static\/|^\/static\/|\/favicon/
62
+ builder.use Rad::Assets::StaticFiles, filters
63
+ end
64
+
65
+ # use Rack::Session::Cookie, key: 'rack.session', domain: 'foo.com', path: '/', expire_after: 2592000, secret: 'change_me'
66
+ builder.use Rack::Session::Cookie, rad.http.session.stringify_keys if rad.http.session
67
+
68
+ # builder.use Rack::CommonLogger
69
+ builder.use Rack::MethodOverride
70
+ end
@@ -0,0 +1,56 @@
1
+ #
2
+ # Processor
3
+ #
4
+ class Rad::Processors::PrepareAutenticityToken < Rad::Conveyors::Processor
5
+ def call
6
+ if rad.http.session
7
+ request = workspace.request.must_be.defined
8
+ params = workspace.params.must_be.defined
9
+
10
+ token = request.session['authenticity_token']
11
+
12
+ if token.blank? and request.get? and
13
+ token = generate_authenticity_token
14
+ request.session['authenticity_token'] = token
15
+ end
16
+ end
17
+
18
+ next_processor.call
19
+ end
20
+
21
+
22
+ protected
23
+ def generate_authenticity_token
24
+ ActiveSupport::SecureRandom.base64(32)
25
+ end
26
+ end
27
+
28
+
29
+ #
30
+ # Controller
31
+ #
32
+ Rad::Controller::Http.include Rad::Controller::ForgeryProtector
33
+
34
+ Rad::Controller::Http::ClassMethods.class_eval do
35
+ def protect_from_forgery options = {}
36
+ before :protect_from_forgery, options
37
+ end
38
+ end
39
+
40
+
41
+ #
42
+ # View
43
+ #
44
+ Rad::Html::FormHelper.class_eval do
45
+ def authenticity_token
46
+ @authenticity_token
47
+ end
48
+
49
+ alias_method :form_tag_without_at, :form_tag
50
+ def form_tag *args, &b
51
+ form_tag_without_at *args do
52
+ concat(hidden_field_tag('authenticity_token', authenticity_token) + "\n") if authenticity_token
53
+ b.call if b
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ %w(
2
+ configurators
3
+ extensions
4
+ protect_from_forgery
5
+ ).each{|f| require "rad_ext/#{f}"}
@@ -0,0 +1,4 @@
1
+ module Rad::Controller::ForgeryProtector
2
+ def protect_from_forgery; end
3
+ end
4
+
@@ -0,0 +1,18 @@
1
+ require 'rake_ext'
2
+ require 'ruby_ext'
3
+
4
+ task :environment do
5
+ require 'rad'
6
+ rad.mode = ENV['m'] || ENV['mode'] || ENV['env'] || ENV['environment'] || :development
7
+ rad.runtime_path = File.expand_path '.'
8
+
9
+ require 'rad_ext'
10
+ rad.web
11
+
12
+ require 'rad_ext/utils/cli_helper'
13
+
14
+ Rad::CliHelper.use_runtime_path!
15
+
16
+ load "./init.rb"
17
+ rad.environment
18
+ end
@@ -0,0 +1,34 @@
1
+ module Rad::CliHelper
2
+ RUNTIME_DIR = 'runtime'
3
+
4
+ class << self
5
+ inject logger: :logger
6
+
7
+ def run_console
8
+ prepare_running_environment
9
+
10
+ require 'irb'
11
+ IRB.start
12
+ end
13
+
14
+ def run_server
15
+ app = prepare_running_environment
16
+
17
+ rad.http.run app, rad.http.host, rad.http.port
18
+ end
19
+
20
+ def use_runtime_path!
21
+ runtime_path = "./#{RUNTIME_DIR}"
22
+ Dir.chdir runtime_path if Dir.exist? runtime_path
23
+ end
24
+
25
+ protected
26
+ def prepare_running_environment
27
+ use_runtime_path!
28
+
29
+ require 'rack'
30
+ app, options = Rack::Builder.parse_file 'config.ru'
31
+ app
32
+ end
33
+ end
34
+ end
data/lib/rad_ext.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rad'
2
+ require 'rad_ext/gems'
3
+
4
+ lib_dir = __FILE__.dirname
5
+ autoload_dir lib_dir
6
+
7
+ rad.must_not.include :web
8
+ rad.register :web, depends_on: [:html, :router, :controller, :http] do
9
+ require 'rad/core_web/_require'
10
+ require 'rad_ext/require'
11
+
12
+ load 'rad_ext/profiles/web_ext.rb'
13
+ load 'rad/profiles/mailer.rb'
14
+
15
+ rad.assets
16
+
17
+ true
18
+ end
data/readme.md ADDED
@@ -0,0 +1,12 @@
1
+ # Extensions for the Rad framework.
2
+
3
+ - face - tools for rapid interface creation.
4
+ - common_interface - common user interface for Rad.
5
+ - rad_ext - additions and extensions of the Rad.
6
+ - rad_js - JS plugin for the Rad.
7
+ - rad - Rapid Application Development tool built upon of the Rad.
8
+
9
+ Please go to specs for docs.
10
+
11
+ P.S.
12
+ All these components will be in standalone gems, but right now it's simpler for me to hold all of them in one place.
@@ -0,0 +1,5 @@
1
+ en:
2
+ name: "Name"
3
+ comments:
4
+ one: "%{count} comment"
5
+ many: "%{count} comments"
@@ -0,0 +1,7 @@
1
+ ru:
2
+ name: "Имя"
3
+ comments_count:
4
+ one: "%{count} комментарий"
5
+ few: "%{count} комментария"
6
+ many: "%{count} комментариев"
7
+ other: "%{count} комментариев"
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper_with_rad"
4
+
5
+ describe 'I18n' do
6
+ before :all do
7
+ rad.web
8
+ rad.reset :conveyors
9
+
10
+ I18n.load_path += Dir["#{spec_dir}/locales/*/*.{rb,yml}"]
11
+ end
12
+
13
+ def t *args
14
+ I18n.t *args
15
+ end
16
+
17
+ it "basic" do
18
+ I18n.locale = 'en'
19
+ t(:name).should == "Name"
20
+ t(:name).is_a?(String).should be_true
21
+
22
+ I18n.locale = 'ru'
23
+ t(:name).should == "Имя"
24
+ end
25
+
26
+ it "pluggable pluralization" do
27
+ I18n.locale = 'ru'
28
+ t(:comments_count, count: 1).should == "1 комментарий"
29
+ t(:comments_count, count: 2).should == "2 комментария"
30
+ t(:comments_count, count: 5).should == "5 комментариев"
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper_with_rad"
2
+
3
+ describe "User Error" do
4
+ rad.web
5
+ rad.reset :conveyors
6
+ isolate :conveyors, before: :all
7
+
8
+ before :all do
9
+ load 'spec_helper/web_profile.rb'
10
+
11
+ class ::SomeModel
12
+ def self.find! id
13
+ id.should == 'some id'
14
+ SomeModel.new
15
+ end
16
+ end
17
+ end
18
+ after :all do
19
+ remove_constants %w(SomeModel ControllerSpec)
20
+ end
21
+
22
+ it "user error" do
23
+ class ::ControllerSpec
24
+ inherit Rad::Controller::Http
25
+
26
+ prepare_model SomeModel, id: :some_model, variable: 'some_model'
27
+
28
+ def action
29
+ @some_model.should_not == nil
30
+ render inline: 'ok'
31
+ end
32
+ end
33
+
34
+ ccall(ControllerSpec, :action, some_model: 'some id').should == 'ok'
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper_with_rad"
2
+
3
+ describe "User Error" do
4
+ rad.web
5
+ rad.reset :conveyors
6
+
7
+ isolate :conveyors, before: :all
8
+
9
+ before(:all){load 'spec_helper/web_profile.rb'}
10
+
11
+ after :all do
12
+ remove_constants %w(UserErrorSpec)
13
+ end
14
+
15
+ it "user error" do
16
+ class ::UserErrorSpec
17
+ inherit Rad::Controller::Http
18
+
19
+ def call
20
+ raise_user_error "some error"
21
+ end
22
+
23
+ protected
24
+ def catch_user_error
25
+ begin
26
+ yield
27
+ rescue UserError => ue
28
+ render inline: "Catched #{ue.message}"
29
+ end
30
+ end
31
+ around :catch_user_error
32
+ end
33
+
34
+ ccall(UserErrorSpec, :call).should == "Catched some error"
35
+ end
36
+ end
@@ -0,0 +1,188 @@
1
+ require "spec_helper_with_rad"
2
+
3
+ describe "Forgery protection" do
4
+ rad.web
5
+ rad.reset :conveyors
6
+
7
+ with_prepare_params
8
+
9
+ isolate :conveyors
10
+
11
+ before :all do
12
+ class ForgerySpecHelper < Rad::Conveyors::Processor
13
+ def call
14
+ block = workspace.check_forgery.before_request
15
+ block.call workspace if block
16
+ workspace.before_request_done = true
17
+
18
+ next_processor.call
19
+
20
+ block = workspace.check_forgery.after_request
21
+ block.call workspace if block
22
+ workspace.after_request_done = true
23
+ end
24
+ end
25
+
26
+ rad.conveyors.web do |web|
27
+ web.use Rad::Http::Processors::PrepareParams
28
+ web.use Rad::Http::Processors::EvaluateFormat
29
+ web.use ForgerySpecHelper
30
+ web.use Rad::Processors::PrepareAutenticityToken
31
+ web.use Rad::Controller::Processors::ControllerCaller
32
+ end
33
+
34
+ class ::AnRemote
35
+ inherit Rad::Controller::Http
36
+
37
+ protect_from_forgery only: :protected_method
38
+
39
+ def protected_method
40
+ render inline: 'protected result'
41
+ end
42
+
43
+ def method_without_protection
44
+ render inline: 'result'
45
+ end
46
+
47
+ def dumb_method; end
48
+ end
49
+ end
50
+
51
+ after :all do
52
+ rad.reset :conveyors
53
+ remove_constants %w(AnRemote ForgerySpecHelper)
54
+ end
55
+
56
+ before do
57
+ rad.http.stub(:session).and_return({'key' => 'session_id'})
58
+ end
59
+
60
+ def check_forgery opt
61
+ workspace = nil
62
+
63
+ result = rad.http.call(rad.http.mock_environment, check_forgery: opt.to_openobject) do |c|
64
+ c.call
65
+ workspace = rad[:workspace]
66
+ end
67
+
68
+ workspace.before_request_done.should be_true
69
+ workspace.after_request_done.should be_true
70
+ workspace
71
+ end
72
+
73
+ it "should set :authenticity_token only for :get and 'html' request" do
74
+ check_forgery(
75
+ before_request: lambda{|workspace|
76
+ workspace.env['REQUEST_METHOD'] = 'GET'
77
+ workspace.env['CONTENT_TYPE'] = 'text/html'
78
+ workspace.class = AnRemote
79
+ workspace.method_name = :dumb_method
80
+ },
81
+ after_request: lambda{|workspace|
82
+ workspace.request.session['authenticity_token'].should_not be_blank
83
+ }
84
+ )
85
+
86
+ # post
87
+ check_forgery(
88
+ before_request: lambda{|workspace|
89
+ workspace.env['REQUEST_METHOD'] = 'POST'
90
+ workspace.env['CONTENT_TYPE'] = 'text/html'
91
+ workspace.class = AnRemote
92
+ workspace.method_name = :dumb_method
93
+ },
94
+ after_request: lambda{|workspace|
95
+ workspace.request.session['authenticity_token'].should be_blank
96
+ }
97
+ )
98
+ end
99
+
100
+ it "should check any non :get request with browser's formats for :authenticity_token" do
101
+ lambda{
102
+ check_forgery(
103
+ before_request: lambda{|workspace|
104
+ workspace.env['REQUEST_METHOD'] = 'POST'
105
+ workspace.env['CONTENT_TYPE'] = 'text/html'
106
+ workspace.class = AnRemote
107
+ workspace.method_name = 'protected_method'
108
+ }
109
+ )
110
+ }.should raise_error(/invalid authenticity token/)
111
+ end
112
+
113
+ it "should pass request with correct authenticity_token" do
114
+ check_forgery(
115
+ before_request: lambda{|workspace|
116
+ workspace.env['REQUEST_METHOD'] = 'POST'
117
+ workspace.env['CONTENT_TYPE'] = 'text/html'
118
+ workspace.request.session['authenticity_token'] = 'secure token'
119
+ workspace.params['authenticity_token'] = 'secure token'
120
+ workspace.class = AnRemote
121
+ workspace.method_name = 'protected_method'
122
+ },
123
+ after_request: lambda{|workspace|
124
+ workspace.content.should == "protected result"
125
+ }
126
+ )
127
+ end
128
+
129
+ it "should not check request with non-browser content type" do
130
+ check_forgery(
131
+ before_request: lambda{|workspace|
132
+ workspace.env['REQUEST_METHOD'] = 'POST'
133
+ workspace.env['CONTENT_TYPE'] = 'non-browser-format'
134
+ workspace.class = AnRemote
135
+ workspace.method_name = 'protected_method'
136
+ },
137
+ after_request: lambda{|workspace|
138
+ workspace.content.should == "protected result"
139
+ }
140
+ )
141
+ end
142
+
143
+ it "should not check request with non-browser format" do
144
+ check_forgery(
145
+ before_request: lambda{|workspace|
146
+ workspace.env['REQUEST_METHOD'] = 'POST'
147
+ workspace.env['CONTENT_TYPE'] = 'text/html'
148
+ workspace.params['format'] = 'json'
149
+ workspace.class = AnRemote
150
+ workspace.method_name = 'protected_method'
151
+ },
152
+ after_request: lambda{|workspace|
153
+ workspace.content.should == "protected result"
154
+ }
155
+ )
156
+ end
157
+
158
+ it "should not protect non protected methods" do
159
+ check_forgery(
160
+ before_request: lambda{|workspace|
161
+ workspace.env['REQUEST_METHOD'] = 'POST'
162
+ workspace.env['CONTENT_TYPE'] = 'text/html'
163
+ workspace.class = AnRemote
164
+ workspace.method_name = 'method_without_protection'
165
+ },
166
+ after_request: lambda{|workspace|
167
+ workspace.content.should == "result"
168
+ }
169
+ )
170
+ end
171
+
172
+ # it "OUTDATED should use :session_authenticity_token from params (for flash support)" do
173
+ # check_forgery(
174
+ # before_request: lambda{|workspace|
175
+ # workspace.env['REQUEST_METHOD'] = 'POST'
176
+ # workspace.params.format = 'text/html'
177
+ # # workspace.params['session_authenticity_token'] = 'secure token'
178
+ # workspace.params['authenticity_token'] = 'secure token'
179
+ # workspace.class = AnRemote
180
+ # workspace.method_name = 'protected_method'
181
+ # },
182
+ # after_request: lambda{|workspace|
183
+ # workspace.content.should == "protected result"
184
+ # }
185
+ # )
186
+ # end
187
+
188
+ end
@@ -0,0 +1,3 @@
1
+ rad.conveyors.web do |web|
2
+ web.use Rad::Controller::Processors::ControllerCaller
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec_ext'
2
+ require 'rad_ext'
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rad'
4
+ require 'rad/spec'
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rad_ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alexey Petrushin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-04 00:00:00.000000000 +04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: i18n
17
+ requirement: &2956510 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - =
21
+ - !ruby/object:Gem::Version
22
+ version: 0.5.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2956510
26
+ - !ruby/object:Gem::Dependency
27
+ name: rad_core
28
+ requirement: &2956210 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *2956210
37
+ - !ruby/object:Gem::Dependency
38
+ name: rad_assets
39
+ requirement: &2955960 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *2955960
48
+ description:
49
+ email:
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - Rakefile
55
+ - readme.md
56
+ - lib/rad/configurators/abstract.rb
57
+ - lib/rad/configurators/runtime.rb
58
+ - lib/rad/configurators/web.rb
59
+ - lib/rad/controller/forgery_protector.rb
60
+ - lib/rad/processors/ajax_helper.rb
61
+ - lib/rad/processors/ensure_no_www.rb
62
+ - lib/rad_ext/configurators.rb
63
+ - lib/rad_ext/extensions/i18n/locales/ru/pluralization.rb
64
+ - lib/rad_ext/extensions/i18n.rb
65
+ - lib/rad_ext/extensions/prepare_model.rb
66
+ - lib/rad_ext/extensions/user_error.rb
67
+ - lib/rad_ext/extensions.rb
68
+ - lib/rad_ext/gems.rb
69
+ - lib/rad_ext/profiles/web_ext.rb
70
+ - lib/rad_ext/protect_from_forgery.rb
71
+ - lib/rad_ext/require.rb
72
+ - lib/rad_ext/spec.rb
73
+ - lib/rad_ext/tasks.rb
74
+ - lib/rad_ext/utils/cli_helper.rb
75
+ - lib/rad_ext.rb
76
+ - spec/extensions/i18n_spec/locales/en/general.yml
77
+ - spec/extensions/i18n_spec/locales/ru/general.yml
78
+ - spec/extensions/i18n_spec.rb
79
+ - spec/extensions/prepare_model_spec.rb
80
+ - spec/extensions/user_error_spec.rb
81
+ - spec/processors/protect_from_forgery_spec.rb
82
+ - spec/spec_helper/web_profile.rb
83
+ - spec/spec_helper.rb
84
+ - spec/spec_helper_with_rad.rb
85
+ has_rdoc: true
86
+ homepage: http://github.com/alexeypetrushin/rad_ext
87
+ licenses: []
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 1.5.1
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: Extensions for Rad Framework
110
+ test_files: []