optin_parsing 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/CHANGELOG +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/Rakefile +1 -0
- data/lib/optin_parsing.rb +5 -0
- data/lib/optin_parsing/controller_additions.rb +98 -0
- data/lib/optin_parsing/railtie.rb +18 -0
- data/lib/optin_parsing/version.rb +3 -0
- data/optin_parsing.gemspec +24 -0
- data/spec/optin_parsing_spec.rb +144 -0
- data/spec/spec_helper.rb +21 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0dba66eb4acade9c0e1b6178f68c9ed4acf64b51
|
4
|
+
data.tar.gz: 7291ad94416495756a203944f098e61c6e067be8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ae20475ce706fe259e27049b5db4f640fb250e4b9ab1f55ee882e9b23322f4ba11fb504b35dc8c5f51b6e590518337046bce9ce986fea432891e6d5a183e3c1c
|
7
|
+
data.tar.gz: 85af8e502ce6308214b24b9b2b947cf82dd286bd65ef6b2d761f4ab59bb6aeb7ae6f9a9dabe9baa2254220bfb0eb8d9024eec80ecef664dbc1b7f037deab47e2
|
data/.gitignore
ADDED
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Frederick Cheung
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# OptinParsing
|
2
|
+
|
3
|
+
Automatic parsing of json and xml request bodies requires care. Beyond vulnerabilities in the parameter parsing code itself the ability for a requester to be able to control the type of parameters combines badly with some of mysql's typecasting logic, for example
|
4
|
+
|
5
|
+
User.find_by_secret_token(0)
|
6
|
+
|
7
|
+
returns a user with a secret token that does not look to mysql like a valid integer instead of returning nil. Rails 3.2.12 contains some mitigations for this (the above example does not work on rails 3.2.12 and above) but can't catch all cases. You can avoid this by calling `to_s` on parameters that should be strings. For more details see the [security advisory](http://groups.google.com/group/rubyonrails-security/browse_thread/thread/64e747e461f98c25). It is easy to forget to do this and it goes against the philosophy of "secure by default".
|
8
|
+
|
9
|
+
An easy mitigation is to simply disable this parsing by removing mime types from `ActionDispatch::ParamsParser::DEFAULT_PARSERS` this is a change that affects all controllers.
|
10
|
+
|
11
|
+
This gem allows the automatic parameter parsing to be turned on per controller and per action, so that (for example) api endpoints that need to accept json and/or xml can continue to work (and be audited for their parameter usage) but reducing the surface of attack by not allowing json bodies for all those requests that do not need it.
|
12
|
+
|
13
|
+
The default is for such parsing to be disabled for all controllers.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
gem 'optin_parsing'
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install optin_parsing
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Allow a controller to parse xml bodies automatically
|
32
|
+
|
33
|
+
class MyController < ApplicationController
|
34
|
+
parses :xml
|
35
|
+
end
|
36
|
+
|
37
|
+
Allow a controller to parse json bodies automatically, only for a certain action
|
38
|
+
|
39
|
+
class MyController < ApplicationController
|
40
|
+
parses :json, :only => :some_action
|
41
|
+
end
|
42
|
+
|
43
|
+
Allow a controller to parse json bodies automatically, except for certain actions
|
44
|
+
|
45
|
+
class MyController < ApplicationController
|
46
|
+
parses :json, :except => [:some_exempt_action, :another_exempt_action]
|
47
|
+
end
|
48
|
+
|
49
|
+
Allow a controller to parse a specific mime type, with a custom strategy
|
50
|
+
|
51
|
+
class MyController < ApplicationController
|
52
|
+
parses Mime::YAML do |raw_post|
|
53
|
+
#parse raw_post and return a hash of data
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Subclasses inherit their parent classes' settings
|
58
|
+
|
59
|
+
## Caveats
|
60
|
+
|
61
|
+
Ordinarily parameters are parsed by a Rack middleware. This gem defers parsing until the request is processed by the controller: the parsed parameters will not be available to middleware code that runs before this.
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module OptinParsing
|
2
|
+
module ControllerAdditions
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :parse_strategies
|
7
|
+
self.parse_strategies = {}
|
8
|
+
hide_action :decode_formatted_parameters
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# Declares that you want to parse a specific body type, for this controller and its subclasses
|
13
|
+
# You can either pass the symbols +:xml+ or +:json+ or an instance of Mime::Type. If you pass
|
14
|
+
# a Mime::Type you must also supply a block. The block will be passed the request raw post data
|
15
|
+
# and should return a hash of parsed parameter data
|
16
|
+
#
|
17
|
+
# You can also supply a hash of options containing the keys +:except+ or +:only+ to restrict which
|
18
|
+
# actions will be parsed
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# @param [Symbol, Mime::Type] mime_type_or_short_cut
|
22
|
+
# @option options [Array,Symbol] :except A list of actions for which parsing should not be enabled
|
23
|
+
# @option options [Array,Symbol] :only A list of actions for which parsing should be enabled
|
24
|
+
|
25
|
+
def parses mime_type_or_short_cut, options={}, &block
|
26
|
+
|
27
|
+
case mime_type_or_short_cut
|
28
|
+
when Mime::Type
|
29
|
+
raise ArgumentError, "You must supply a block when specifying a mime type" unless block
|
30
|
+
self.parse_strategies = parse_strategies.merge(mime_type_or_short_cut => [block, normalize_optin_options(options)])
|
31
|
+
when :xml
|
32
|
+
self.parse_strategies = parse_strategies.merge(Mime::XML => [:xml, normalize_optin_options(options)])
|
33
|
+
when :json
|
34
|
+
self.parse_strategies = parse_strategies.merge(Mime::JSON => [:json, normalize_optin_options(options)])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
private
|
38
|
+
|
39
|
+
def normalize_optin_options options
|
40
|
+
options.each_with_object({}) do |(key,value), options|
|
41
|
+
options[key] = Array(value).collect {|action_name| action_name.to_s}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_action(method_name, *args)
|
47
|
+
strategy, options = parse_strategies[request.content_mime_type]
|
48
|
+
if strategy
|
49
|
+
if should_decode_body(options)
|
50
|
+
if data = decode_formatted_parameters(strategy)
|
51
|
+
params.merge!(data)
|
52
|
+
log_parsed(apply_filter_parameters(data))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def should_decode_body options
|
62
|
+
if options[:only]
|
63
|
+
options[:only].include?(action_name)
|
64
|
+
elsif options[:except]
|
65
|
+
!options[:except].include?(action_name)
|
66
|
+
else
|
67
|
+
true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def decode_formatted_parameters(strategy)
|
72
|
+
case strategy
|
73
|
+
when Proc
|
74
|
+
strategy.call(request.raw_post)
|
75
|
+
when :xml
|
76
|
+
data = request.deep_munge(Hash.from_xml(request.body.read) || {})
|
77
|
+
request.body.rewind if request.body.respond_to?(:rewind)
|
78
|
+
data.with_indifferent_access
|
79
|
+
when :json
|
80
|
+
data = request.deep_munge ActiveSupport::JSON.decode(request.body.read)
|
81
|
+
request.body.rewind if request.body.respond_to?(:rewind)
|
82
|
+
data = {:_json => data} unless data.is_a?(Hash)
|
83
|
+
data.with_indifferent_access
|
84
|
+
else
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def log_parsed(data)
|
90
|
+
Rails.logger.info "Parsed #{request.content_mime_type}: #{data.inspect}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def apply_filter_parameters(data)
|
94
|
+
parameter_filter = ActionDispatch::Http::ParameterFilter.new(Rails.configuration.filter_parameters)
|
95
|
+
parameter_filter.filter(data)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "optin_parsing"
|
2
|
+
require "rails"
|
3
|
+
|
4
|
+
module OptinParsing
|
5
|
+
# = OptinParsing Railtie
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
|
8
|
+
initializer "optinparsing.inject_modules" do |app|
|
9
|
+
ActiveSupport.on_load(:action_controller) do
|
10
|
+
ActionController::Base.send :include, OptinParsing::ControllerAdditions
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
initializer "optinparsing.remove_default_parsers" do |app|
|
15
|
+
config.app_middleware.delete '::ActionDispatch::ParamsParser'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'optin_parsing/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "optin_parsing"
|
8
|
+
gem.version = OptinParsing::VERSION
|
9
|
+
gem.authors = ["Frederick Cheung"]
|
10
|
+
gem.email = ["frederick.cheung@gmail.com"]
|
11
|
+
gem.description = %q{Mitigate the dangers of automatic json/xml parsing by only enabling them for the controllers & actions that require it}
|
12
|
+
gem.summary = %q{Mitigate the dangers of automatic json/xml parsing by only enabling them for the controllers & actions that require it}
|
13
|
+
gem.homepage = "https://github.com/fcheung/optin_parsing"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency "rspec", "~>2.10"
|
21
|
+
gem.add_development_dependency "rspec-rails", "~>2.10"
|
22
|
+
gem.add_development_dependency "rspec-instafail"
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'optin_parsing controller with controller additions included', :type => :controller do
|
4
|
+
include Rails.application.routes.url_helpers
|
5
|
+
module Actions
|
6
|
+
def index
|
7
|
+
@parsed_params = params.except(:controller, :action)
|
8
|
+
head :ok
|
9
|
+
end
|
10
|
+
|
11
|
+
def new
|
12
|
+
@parsed_params = params.except(:controller, :action)
|
13
|
+
head :ok
|
14
|
+
end
|
15
|
+
|
16
|
+
def _routes
|
17
|
+
@routes
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def json
|
23
|
+
'{"test": "value"}'
|
24
|
+
end
|
25
|
+
|
26
|
+
def xml
|
27
|
+
'<?xml version="1.0" encoding="UTF-8"?><test>value</test>'
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when the module is included' do
|
31
|
+
def self.preconfigured_controller(&block)
|
32
|
+
controller(ActionController::Base) do
|
33
|
+
include OptinParsing::ControllerAdditions
|
34
|
+
include Actions
|
35
|
+
instance_eval(&block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'parsing is not enabled' do
|
40
|
+
preconfigured_controller {}
|
41
|
+
|
42
|
+
it { should_not parse_parameters.of_type(Mime::JSON).for_action(:index).with_body(json) }
|
43
|
+
it { should_not parse_parameters.of_type(Mime::XML).for_action(:index).with_body(xml) }
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'parsing of xml is enabled' do
|
47
|
+
context 'unconditionally' do
|
48
|
+
preconfigured_controller do
|
49
|
+
parses :xml
|
50
|
+
end
|
51
|
+
|
52
|
+
it { should_not parse_parameters.of_type(Mime::JSON).for_action(:index).with_body(json) }
|
53
|
+
it { should parse_parameters.of_type(Mime::XML).for_action(:index).with_body(xml) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'parsing of a custom type is enabled' do
|
58
|
+
preconfigured_controller do
|
59
|
+
parses Mime::YAML do |body|
|
60
|
+
YAML.load(body)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
it { should parse_parameters.of_type(Mime::YAML).for_action(:index).with_body({'test' => 'value'}.to_yaml) }
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'parsing of json is enabled' do
|
67
|
+
context 'unconditionally' do
|
68
|
+
preconfigured_controller do
|
69
|
+
parses :json
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'logs parsed parameters honouring filter_parameters config' do
|
73
|
+
request.env['RAW_POST_DATA'] = json
|
74
|
+
request.env['CONTENT_TYPE'] = Mime::JSON.to_s
|
75
|
+
Rails.configuration.filter_parameters = [:test]
|
76
|
+
|
77
|
+
controller.should_receive(:log_parsed).with({'test' => '[FILTERED]'})
|
78
|
+
|
79
|
+
put :index
|
80
|
+
end
|
81
|
+
|
82
|
+
it { should parse_parameters.of_type(Mime::JSON).for_action(:index).with_body(json) }
|
83
|
+
it { should_not parse_parameters.of_type(Mime::XML).for_action(:index).with_body(xml) }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'an only option is specified' do
|
87
|
+
preconfigured_controller do
|
88
|
+
parses :json, :only => :index
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'the action is contained in the list' do
|
92
|
+
it { should parse_parameters.of_type(Mime::JSON).for_action(:index).with_body(json) }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'the action is not contained in the list' do
|
96
|
+
it { should_not parse_parameters.of_type(Mime::JSON).for_action(:new).with_body(json) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'an except option is specified' do
|
101
|
+
preconfigured_controller do
|
102
|
+
parses :json, :except => :index
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'the action is contained in the list' do
|
106
|
+
it { should_not parse_parameters.of_type(Mime::JSON).for_action(:index).with_body(json) }
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'the action is not contained in the list' do
|
110
|
+
it { should parse_parameters.of_type(Mime::JSON).for_action(:new).with_body(json) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
RSpec::Matchers.define :parse_parameters do |y|
|
119
|
+
|
120
|
+
chain :of_type do |mime_type|
|
121
|
+
@mime_type = mime_type
|
122
|
+
end
|
123
|
+
|
124
|
+
chain :for_action do |action_name|
|
125
|
+
@action_name = action_name
|
126
|
+
end
|
127
|
+
|
128
|
+
chain :with_body do |body|
|
129
|
+
@body = body
|
130
|
+
end
|
131
|
+
|
132
|
+
match do
|
133
|
+
@expected = {'test' => 'value'}
|
134
|
+
request.env['RAW_POST_DATA'] = @body
|
135
|
+
request.env['CONTENT_TYPE'] = @mime_type.to_s
|
136
|
+
put @action_name.to_sym
|
137
|
+
@actual = assigns(:parsed_params)
|
138
|
+
@actual == @expected
|
139
|
+
end
|
140
|
+
|
141
|
+
failure_message_for_should do
|
142
|
+
"Expected parameters #{@expected} got #{@actual}"
|
143
|
+
end
|
144
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rails/all'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
7
|
+
|
8
|
+
require 'optin_parsing'
|
9
|
+
require 'action_controller'
|
10
|
+
require 'rspec/rails'
|
11
|
+
|
12
|
+
module DummyApplication
|
13
|
+
class Application < Rails::Application
|
14
|
+
config.secret_token = '*******************************'
|
15
|
+
config.logger = Logger.new(File.expand_path('../test.log', __FILE__))
|
16
|
+
Rails.logger = config.logger
|
17
|
+
end
|
18
|
+
end
|
19
|
+
RSpec.configure do |config|
|
20
|
+
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: optin_parsing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Frederick Cheung
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-instafail
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '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'
|
55
|
+
description: Mitigate the dangers of automatic json/xml parsing by only enabling them
|
56
|
+
for the controllers & actions that require it
|
57
|
+
email:
|
58
|
+
- frederick.cheung@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- CHANGELOG
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- lib/optin_parsing.rb
|
70
|
+
- lib/optin_parsing/controller_additions.rb
|
71
|
+
- lib/optin_parsing/railtie.rb
|
72
|
+
- lib/optin_parsing/version.rb
|
73
|
+
- optin_parsing.gemspec
|
74
|
+
- spec/optin_parsing_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
homepage: https://github.com/fcheung/optin_parsing
|
77
|
+
licenses: []
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.2.2
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Mitigate the dangers of automatic json/xml parsing by only enabling them
|
99
|
+
for the controllers & actions that require it
|
100
|
+
test_files:
|
101
|
+
- spec/optin_parsing_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
has_rdoc:
|