padrino-csrf 0.1.0

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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ archive/*
3
+ doc/*
4
+ .yardoc
5
+ .bundle
6
+ Gemfile.lock
data/.yardopts ADDED
@@ -0,0 +1,9 @@
1
+ --no-save
2
+ --no-private
3
+ --title Padrino Cross-Site Request Forgery
4
+ --markup-provider redcarpet
5
+ --markup markdown
6
+ lib/**/*.rb
7
+ -
8
+ README.md
9
+ LICENSE
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Benjamin Bloch
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ ### Overview
2
+
3
+ Padrino CSRF is a plugin for the [Padrino](https://github.com/padrino/padrino-framework) web framework which adds [cross-site request forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery) protection.
4
+
5
+ ### Setup & Installation
6
+
7
+ Include it in your project's `Gemfile` with Bundler:
8
+
9
+ ``` ruby
10
+ gem 'padrino-csrf'
11
+ ```
12
+
13
+ Modify your `app/app.rb` file to register the plugin:
14
+
15
+ ``` ruby
16
+ class ExampleApplication < Padrino::Application
17
+ register Padrino::CSRF
18
+ end
19
+ ```
20
+
21
+ ### Configuration
22
+
23
+ `prevent_request_forgery`
24
+ When enabled, will automatically verify the CSRF authentication token on all `post`, `put`, and `delete` requests.
25
+
26
+ You can of course disable this on a request by request basis:
27
+
28
+ ``` ruby
29
+ enable :prevent_request_forgery
30
+
31
+ post :register do
32
+ # request is checked
33
+ end
34
+
35
+ post :register, protect: false do
36
+ # request isn't checked
37
+ end
38
+ ```
39
+
40
+ Or if you prefer, you can disable it by default, and enable it on a request by request basis:
41
+
42
+ ``` ruby
43
+ disable :prevent_request_forgery
44
+
45
+ post :register do
46
+ # request isn't checked
47
+ end
48
+
49
+ post :register, protect: true do
50
+ # request is checked
51
+ end
52
+ ```
53
+
54
+ ### Dependencies
55
+
56
+ * [Padrino-Core](https://github.com/padrino/padrino-framework) and [Padrino-Helpers](https://github.com/padrino/padrino-framework)
57
+ * [Ruby](http://www.ruby-lang.org/en) >= 1.9.2
58
+
59
+ ### TODO
60
+
61
+ * Additional documentation
62
+ * Tests
63
+
64
+ ### Copyright
65
+
66
+ Copyright � 2012 Benjamin Bloch (Cirex). See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |test|
5
+ test.test_files = FileList['test/**/test_*.rb']
6
+ test.verbose = true
7
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ module Padrino
3
+ module CSRF
4
+ module FormHelpers
5
+ ###
6
+ # Returns a hidden HTML input field with this sessions CSRF token
7
+ #
8
+ # @return [String]
9
+ # Generated HTML for hidden CSRF input field
10
+ #
11
+ # @since 0.1.0
12
+ # @api semipublic
13
+ def token_field_tag
14
+ input_tag(:hidden, name: csrf_param, value: csrf_token)
15
+ end
16
+
17
+ # @private
18
+ def form_tag(url, options = {}, &block)
19
+ super(url, options) { token_field_tag + capture_html(&block) }
20
+ end
21
+ end # FormHelpers
22
+ end # CSRF
23
+ end # Padrino
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+ module Padrino
3
+ module CSRF
4
+ module Helpers
5
+ ###
6
+ # Returns whether or not the CSRF parameter is authentic
7
+ #
8
+ # @return [Boolean]
9
+ # *true* if CSRF is valid, *false* otherwise
10
+ #
11
+ # @since 0.1.0
12
+ # @api semipublic
13
+ def csrf_valid?
14
+ csrf_token == params[csrf_param] || csrf_token == request.env['HTTP_X_CSRF_TOKEN']
15
+ end
16
+
17
+ ###
18
+ # Returns HTML meta tags for use with unobtrusive javascript helpers
19
+ #
20
+ # @return [String]
21
+ # Generated HTML for CSRF meta tags
22
+ #
23
+ # @example
24
+ # csrf_meta_tags
25
+ # # => <meta name="csrf-token" content="71ab53190d2f863b5f3b12381d2d5986512f8e15b34d439e6b66e3daf41b5e35">
26
+ # # => <meta name="csrf-param" content="_csrf_token">
27
+ #
28
+ # @since 0.1.0
29
+ # @api public
30
+ def csrf_meta_tags
31
+ [ meta_tag(csrf_token, name: 'csrf-token'),
32
+ meta_tag(csrf_param, name: 'csrf-param')
33
+ ].join("\n")
34
+ end
35
+
36
+ ###
37
+ # Returns the CSRF authentication token for the current session
38
+ #
39
+ # @return [String]
40
+ # 32 character CSRF token
41
+ #
42
+ # @since 0.1.0
43
+ # @api semipublic
44
+ def csrf_token
45
+ session[csrf_param] ||= SecureRandom.hex(32)
46
+ end
47
+
48
+ # @private
49
+ def csrf_param
50
+ :_csrf_token
51
+ end
52
+ end # Helpers
53
+ end # CSRF
54
+ end # Padrino
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ module Padrino
3
+ module CSRF
4
+ module Routing
5
+ ###
6
+ # Routing condition which lets you manually toggle CSRF authentication
7
+ #
8
+ # @param [Boolean] protect
9
+ # Should the request be authenticated
10
+ #
11
+ # @raise [InvalidToken]
12
+ # Raised when the CSRF parameter is invalid
13
+ #
14
+ # @example
15
+ # enable :prevent_request_forgery
16
+ #
17
+ # post :register do
18
+ # # request is checked
19
+ # end
20
+ #
21
+ # post :register, protect: false do
22
+ # # request isn't checked
23
+ # end
24
+ #
25
+ # @example
26
+ # disable :prevent_request_forgery
27
+ #
28
+ # post :register do
29
+ # # request isn't checked
30
+ # end
31
+ #
32
+ # post :register, protect: true do
33
+ # # request is checked
34
+ # end
35
+ #
36
+ # @since 0.1.0
37
+ # @api public
38
+ def protect(protect = false)
39
+ condition do
40
+ if protect
41
+ raise InvalidToken unless csrf_valid?
42
+ end
43
+ end
44
+ end
45
+
46
+ # @private
47
+ def route(verb, path, options = {}, &block)
48
+ if REQUEST_BLACKLIST.include?(verb)
49
+ options[:protect] = settings.prevent_request_forgery if options[:protect] == nil
50
+ else
51
+ options.delete(:protect)
52
+ end
53
+
54
+ super(verb, path, options, &block)
55
+ end
56
+ end # Routing
57
+ end # CSRF
58
+ end # Padrino
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+ module Padrino
3
+ module CSRF
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ require 'padrino-core'
3
+ require 'padrino-helpers'
4
+
5
+ FileSet.glob_require('padrino-csrf/**/*.rb', __FILE__)
6
+
7
+ module Padrino
8
+ module CSRF
9
+ REQUEST_BLACKLIST = %w(POST PUT DELETE)
10
+
11
+ class InvalidToken < RuntimeError
12
+ # @private
13
+ def http_status
14
+ 403
15
+ end
16
+ end
17
+
18
+ class << self
19
+ # @private
20
+ def registered(app)
21
+ app.helpers Helpers
22
+ app.helpers FormHelpers
23
+ app.enable :prevent_request_forgery
24
+
25
+ app.extend Routing
26
+
27
+ if defined?(Padrino::Assets)
28
+ Padrino::Assets.load_paths << File.expand_path('../../vendor/assets', __FILE__)
29
+ app.precompile_assets << 'jquery.unobtrusive.js'
30
+ end
31
+ end
32
+ end # self
33
+ end # CSRF
34
+ end # Padrino
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'padrino-csrf/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'padrino-csrf'
7
+ s.version = Padrino::CSRF::VERSION
8
+ s.authors = ['Benjamin Bloch']
9
+ s.email = ['cirex@gamesol.org']
10
+ s.homepage = 'https://github.com/Cirex/padrino-csrf'
11
+ s.description = 'A plugin for the Padrino web framework which adds CSRF protection'
12
+ s.summary = s.description
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ['lib']
18
+
19
+ s.add_dependency 'padrino-core'
20
+ s.add_dependency 'padrino-helpers'
21
+
22
+ s.add_development_dependency 'minitest'
23
+ s.add_development_dependency 'webrat'
24
+ end
@@ -0,0 +1,76 @@
1
+ $('form[data-remote=true]').live('submit', function(e) {
2
+ e.preventDefault(); e.stopped = true;
3
+ var element = $(this);
4
+ var message = element.data('confirm');
5
+ if (message && !confirm(message)) { return false; }
6
+ Padrino.sendRequest(element, {
7
+ dataType: element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType) || 'script',
8
+ verb: element.data('method') || element.attr('method') || 'post',
9
+ url: element.attr('action'),
10
+ params: element.serializeArray()
11
+ });
12
+ });
13
+
14
+ $('a[data-confirm]').live('click', function(e) {
15
+ var message = $(this).data('confirm');
16
+ if (!confirm(message)) { e.preventDefault(); e.stopped = true; }
17
+ });
18
+
19
+ $('a[data-remote=true]').live('click', function(e) {
20
+ var element = $(this);
21
+ if (e.stopped) return;
22
+ e.preventDefault(); e.stopped = true;
23
+ Padrino.sendRequest(element, {
24
+ verb: element.data('method') || 'get',
25
+ url: element.attr('href')
26
+ });
27
+ });
28
+
29
+ $('a[data-method]:not([data-remote])').live('click', function(e) {
30
+ if (e.stopped) return;
31
+ Padrino.sendMethod($(e.target));
32
+ e.preventDefault(); e.stopped = true;
33
+ });
34
+
35
+ $.ajaxPrefilter(function(options, originalOptions, xhr){ if (!options.crossDomain) { Padrino.CSRFilter(xhr); }});
36
+
37
+ var Padrino = {
38
+ sendRequest : function(element, options) {
39
+ var verb = options.verb, url = options.url, params = options.params, dataType = options.dataType;
40
+ var event = element.trigger('ajax:before');
41
+ if (event.stopped) return false;
42
+ $.ajax({
43
+ url: url,
44
+ type: verb.toUpperCase() || 'POST',
45
+ data: params || [],
46
+ dataType: dataType,
47
+
48
+ beforeSend: function(request) { element.trigger('ajax:loading', [ request ]); },
49
+ complete: function(request) { element.trigger('ajax:complete', [ request ]); },
50
+ success: function(request) { element.trigger('ajax:success', [ request ]); },
51
+ error: function(request) { element.trigger('ajax:failure', [ request ]); }
52
+ });
53
+ element.trigger('ajax:after');
54
+ },
55
+
56
+ sendMethod : function(element) {
57
+ var verb = element.data('method');
58
+ var url = element.attr('href');
59
+ var csrf_token = $('meta[name=csrf-token]').attr('content');
60
+ var csrf_param = $('meta[name=csrf-param]').attr('content');
61
+
62
+ var form = $('<form method="post" action="' + url + '"></form>');
63
+ form.append('<input type="hidden" name="_method" value="' + verb + '">')
64
+ if (csrf_param !== undefined && csrf_token !== undefined) {
65
+ form.append('<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden">');
66
+ }
67
+
68
+ form.hide().appendTo('body');
69
+ form.submit();
70
+ },
71
+
72
+ CSRFilter: function(xhr) {
73
+ var token = $('meta[name="csrf-token"]').attr('content');
74
+ if (token) { xhr.setRequestHeader('X-CSRF-Token', token); }
75
+ },
76
+ };
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: padrino-csrf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benjamin Bloch
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: padrino-core
16
+ requirement: &18997080 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *18997080
25
+ - !ruby/object:Gem::Dependency
26
+ name: padrino-helpers
27
+ requirement: &18961296 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *18961296
36
+ - !ruby/object:Gem::Dependency
37
+ name: minitest
38
+ requirement: &18729264 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *18729264
47
+ - !ruby/object:Gem::Dependency
48
+ name: webrat
49
+ requirement: &15937272 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *15937272
58
+ description: A plugin for the Padrino web framework which adds CSRF protection
59
+ email:
60
+ - cirex@gamesol.org
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - .yardopts
67
+ - Gemfile
68
+ - LICENSE
69
+ - README.md
70
+ - Rakefile
71
+ - lib/padrino-csrf.rb
72
+ - lib/padrino-csrf/form_helpers.rb
73
+ - lib/padrino-csrf/helpers.rb
74
+ - lib/padrino-csrf/routing.rb
75
+ - lib/padrino-csrf/version.rb
76
+ - padrino-csrf.gemspec
77
+ - vendor/assets/jquery.unobtrusive.js
78
+ homepage: https://github.com/Cirex/padrino-csrf
79
+ licenses: []
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.15
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: A plugin for the Padrino web framework which adds CSRF protection
102
+ test_files: []
103
+ has_rdoc: