rack-simple_csrf 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc1560d053a3c6e140795a8ed52edbab6718888c
4
+ data.tar.gz: c35998ea6d6e873baf8f98bc2fa9dfe9f53c0372
5
+ SHA512:
6
+ metadata.gz: 61ebfca10811016cf01de6267b27ba424efd4b56ef331ddae5a7a60a587d6d4c2fddb2aac581b25a6c4e4da1bdd5c9b7c020c69194e9e855e04deb80233e4e83
7
+ data.tar.gz: 93d11241740bc891deb13389154fc1f64e24a36c7a94493b655cccb2dc4a9d1abdb16c0f56557155fa89fa296ce734375b4ddc88a68111cdec55b05b2af3051e
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
4
+ group :development do
5
+ gem "rake"
6
+ end
data/License ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2013 Jordon Bedwell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "rspec/core/rake_task"
2
+ task :default => :spec
3
+ RSpec::Core::RakeTask.new :spec
data/Readme.md ADDED
@@ -0,0 +1,61 @@
1
+ # Rack::Csrf
2
+
3
+ [![Build Status](https://travis-ci.org/envygeeks/rack-simple_csrf.png?branch=master)](https://travis-ci.org/envygeeks/rack-simple_csrf) [![Coverage Status](https://coveralls.io/repos/envygeeks/rack-simple_csrf/badge.png?branch=master)](https://coveralls.io/r/envygeeks/rack-simple_csrf) [![Code Climate](https://codeclimate.com/github/envygeeks/rack-simple_csrf.png)](https://codeclimate.com/github/envygeeks/rack-simple_csrf) [![Dependency Status](https://gemnasium.com/envygeeks/rack-simple_csrf.png)](https://gemnasium.com/envygeeks/rack-simple_csrf)
4
+
5
+ Rack::SimpleCsrf is my personal version of CSRF for Rack. It implements only a skip list where everything else must be run through the validator. It does not allow you to be explicit in what you validate, only explicit in what you do not validate. The goal is to increase security and make you think about what you are doing before you decide to do it.
6
+
7
+ # Usage
8
+
9
+ Rack::SimpleCsrf has a default output of "Denied", the example belows shows you passing your own caller for us.
10
+
11
+ ```ruby
12
+ require "sinatra/base"
13
+ require "rack/simple_csrf"
14
+ require "logger"
15
+
16
+ class MyApp < Sinatra::Base
17
+ set(:logger, Logger.new($stdout))
18
+
19
+ CSRF_SKIP_LIST = [
20
+ "/my-path",
21
+ "POST:/my-other-path"
22
+ ]
23
+
24
+ class << self
25
+ def denied!(exception)
26
+ MyApp.logger.error { exception }
27
+ [403, {}, ["Nice try asshole!"]]
28
+ end
29
+ end
30
+
31
+ post "/" do
32
+ puts "Hello World"
33
+ end
34
+
35
+ helpers Rack::SimpleCsrf::Helpers
36
+ use Rack::SimpleCsrf, {
37
+ :skip => CSRF_SKIP_LIST,
38
+ :render_with => proc { |*a|
39
+ denied!(*a)
40
+ }
41
+ }
42
+ end
43
+ ```
44
+
45
+ # Options
46
+
47
+ `:header` - `HTTP_X_CSRF_TOKEN` The header key<br />
48
+ `:key` - `csrf` -- The cookie key<br />
49
+ `:field` - `auth` -- The auth_field token (meta and form)<br />
50
+ `:raise` - `false` -- Raise `Rack::SimpleCsrf::CSRFFailedToValidateError`
51
+ <br /><br />
52
+ Skip supports an array with values as "METHOD:/url" or "/url".<br /><br />
53
+
54
+ If you chose not to raise you can optionally set `:render_with` with a callback. The callback will always recieve the `env` for you to call `Rack::Lint` or `Sinatra::Request` yourself. It is done this way so that people who wish to log can log since I don't accept a logger directly, you might also want to do other shit that I don't care about, so rather than giving a shit I might as well just accept a callback and let you do whatever the hell you want.
55
+
56
+ # Helpers
57
+
58
+ ```ruby
59
+ csrf_meta_tag(:field => "auth")
60
+ csrf_form_tag(:tag => "div", :field => "auth")
61
+ ```
data/lib/rack/csrf.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "simple_csrf"
2
+ Rack.const_set(:Csrf, Rack::SimpleCsrf)
@@ -0,0 +1,94 @@
1
+ require_relative "simple_csrf/version"
2
+ require "securerandom"
3
+
4
+ class String
5
+ def strip_heredoc(offset = 0)
6
+ gsub(/^[ \t]{#{(scan(/^[ \t]*(?=\S)/).min || "").size}}/, offset = "\s" * (offset || 0))
7
+ end
8
+ end
9
+
10
+ module Rack
11
+ class SimpleCsrf
12
+ class CSRFSessionUnavailableError < StandardError
13
+ def initialize(msg = nil)
14
+ super msg || "CSRF requires session."
15
+ end
16
+ end
17
+
18
+ class CSRFFailedToValidateError < StandardError
19
+ def initialize(msg = nil)
20
+ super msg || "CSRF did not pass."
21
+ end
22
+ end
23
+
24
+ def initialize(app, opts = {})
25
+ @field = opts.fetch(:field, "auth")
26
+ @raise = opts.fetch(:raise, false)
27
+ @key = opts.fetch(:key, "csrf")
28
+ @skip = opts.fetch(:skip, [])
29
+
30
+ @app = app
31
+
32
+ @render_with = opts[:render_with]
33
+ @header = opts.fetch(:header, "HTTP_X_CSRF_TOKEN")
34
+ @methods = (%w(POST PUT DELETE PATCH) + opts.fetch(:http_methods, [])).flatten.uniq
35
+ end
36
+
37
+ def call(env, req = Rack::Request.new(env))
38
+ raise_if_session_unavailable_for! req
39
+ setup_csrf_for! req
40
+ return @app.call(env) if continue?(req)
41
+ @raise ? raise(CSRFFailedToValidateError) : render_error_for!(env)
42
+ end
43
+
44
+ private
45
+ def continue?(req)
46
+ req.params[@field] == req.env["rack.session"][@key] ||
47
+ req.env[@header] == req.env["rack.session"][@key] ||
48
+ ! @methods.include?(req.request_method) || any_skips?(req)
49
+ end
50
+
51
+ private
52
+ def any_skips?(req)
53
+ (Array === @skip && @skip.any? do |url|
54
+ meth, path = Regexp.escape(req.request_method), Regexp.escape(req.path)
55
+ url =~ /^#{meth}:#{path}$/ || url =~ /^#{path}$/
56
+ end)
57
+ end
58
+
59
+ private
60
+ def raise_if_session_unavailable_for!(req)
61
+ unless req.env["rack.session"]
62
+ raise CSRFSessionUnavailableError
63
+ end
64
+ end
65
+
66
+ private
67
+ def setup_csrf_for!(req)
68
+ req.env["rack.session"][@key] ||= SecureRandom.hex(32)
69
+ end
70
+
71
+ private
72
+ def render_error_for!(env)
73
+ Proc === @render_with ? @render_with.call(env) : [403, {}, ["Unauthorized"]]
74
+ end
75
+
76
+ module Helpers
77
+ extend self
78
+
79
+ def csrf_meta_tag(opts = {}, session = session)
80
+ %Q{<meta name="#{opts[:field] || "auth"}" content="#{session[opts[:key] || "csrf"]}">}
81
+ end
82
+
83
+ def csrf_form_tag(opts = {}, session = session)
84
+ session_key = session[opts[:key] || "csrf"]
85
+ tag = opts[:tag] || "div"
86
+ <<-HTML.strip_heredoc(opts[:offset])
87
+ <#{tag} class="hidden">
88
+ <input type="hidden" name="#{opts[:field] || "auth"}" value="#{session_key}">
89
+ </#{tag}>
90
+ HTML
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class SimpleCsrf
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-simple_csrf
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jordon Bedwell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-expect_error
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: envygeeks-coveralls
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: luna-rspec-formatters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.0'
83
+ description: A simpler CSRF middleware for Rack.
84
+ email:
85
+ - envygeeks@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - Gemfile
91
+ - License
92
+ - Rakefile
93
+ - Readme.md
94
+ - lib/rack/csrf.rb
95
+ - lib/rack/simple_csrf.rb
96
+ - lib/rack/simple_csrf/version.rb
97
+ homepage: https://envygeeks.com/projects/rack-csrf
98
+ licenses: []
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.2.1
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: A simpler CSRF middleware for Rack.
120
+ test_files: []