actiondebug 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,39 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+
36
+ # Ignore vim temp files
37
+ *.swp
38
+ *.swo
39
+ *~
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in lorem.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Blake Hitchcock
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.
@@ -0,0 +1,107 @@
1
+ # actiondebug
2
+ A gem to show which *_filters affect your Rails controllers. Useful for security
3
+ research (which controllers and actions skip an auth check?) and debugging
4
+ development problems (why isn't a method running for a given request?)
5
+
6
+ # Examples
7
+
8
+ ### Sample Application
9
+ ```ruby
10
+ class ApplicationController < ActionController::Base
11
+ before_filter :require_login
12
+ before_filter :refresh_session
13
+
14
+ def index
15
+ end
16
+
17
+ private
18
+ def require_login
19
+ end
20
+
21
+ def refresh_session
22
+ end
23
+ end
24
+
25
+ class SessionsController < ApplicationController
26
+ skip_before_filter :require_login, :except => :active
27
+ before_filter :update_session, :only => :create
28
+ before_filter :destroy_session, :only => :new
29
+
30
+ def index
31
+ end
32
+
33
+ def new
34
+ end
35
+
36
+ def create
37
+ end
38
+
39
+ def active
40
+ end
41
+
42
+ private
43
+ def udpate_session
44
+ end
45
+
46
+ def destroy_session
47
+ end
48
+ end
49
+ ```
50
+
51
+ ### Commands in Rails Console
52
+ ```ruby
53
+ ## Show all actions and filters for controllers which inherit from a controller (including itself)
54
+ > ApplicationController.filters_for_self_and_descendants
55
+ # => {
56
+ # :ApplicationController => {:index => [:require_login, :refresh_session]},
57
+ # :SessionsController => {
58
+ # :index => [:refresh_sesion],
59
+ # :new => [:refresh_session, :destroy_session],
60
+ # :create => [:refresh_session, :update_session],
61
+ # :active => [:require_login, :refresh_session]
62
+ # }
63
+ # }
64
+
65
+ ## Show all filters used by a controller
66
+ > SessionsController.filters
67
+ # => {
68
+ # :index => [:refresh_session],
69
+ # :create => [:refresh_session, :destroy_session],
70
+ # :new => [:refresh_session, :udpate_session],
71
+ # :active => [:require_login, :refresh_session]
72
+ # }
73
+
74
+ ## Show all before filters for a given action
75
+ > SessionsController.before_filters(:new)
76
+ # => {
77
+ # :new => [:refresh_session, :update_session]
78
+ # }
79
+
80
+ ## Show all actions which skip a given filter, scoped to self and descendants
81
+ > ApplicationController.actions_skipping_filter(:require_login)
82
+ # => {
83
+ # :SessionsController => [:index, :new, :create]
84
+ # }
85
+ ```
86
+
87
+ # Installation
88
+ ## Using Bundler
89
+ ```
90
+ # From https://rubygems.org
91
+ gem 'actiondebug', '~> 1.0.0'
92
+
93
+ # From github
94
+ gem 'actiondebug', '~> 1.0.0', git: "https://github.com/rbhitchcock/actiondebug"
95
+ ```
96
+
97
+ ## Standalone Gem
98
+ ```
99
+ gem -v '1.0.0' actiondebug
100
+ ```
101
+
102
+ ## From source
103
+ ```
104
+ > git clone https://github.com/rbhitchcock/actiondebug.git
105
+ > cd actiondebug
106
+ > rake install
107
+ ```
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'actiondebug/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "actiondebug"
8
+ spec.version = ActionDebug::VERSION
9
+ spec.authors = ["Blake Hitchcock"]
10
+ spec.email = ["rbhitchcock@gmail.com"]
11
+ spec.summary = "A gem to show which *_filters affect your Rails controllers"
12
+ spec.description = <<-EOF
13
+ actiondebug is a utility that can give you more insight
14
+ into the structure of your Rails application. It can show all filters that
15
+ a controller is using, grouped by action. It can also report which actions
16
+ skip a given filter. Its extendability is essentially endless. Great tool
17
+ for security researchers and developers alike.
18
+ EOF
19
+ spec.homepage = "https://github.com/rbhitchcock/actiondebug"
20
+ spec.license = "MIT"
21
+
22
+ spec.files = `git ls-files -z`.split("\x0")
23
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.5"
28
+ spec.add_development_dependency "rake"
29
+ end
@@ -0,0 +1,4 @@
1
+ if defined? Rails
2
+ require 'actiondebug/controller'
3
+ require 'actiondebug/railtie'
4
+ end
@@ -0,0 +1,148 @@
1
+ module ActionDebug
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # With current knowledge of Rails internals, we are going to have to call
7
+ # this method several times when building up a map of the entire
8
+ # application.
9
+ def filters(p = {})
10
+ if p[:action].nil?
11
+ action_methods(false).reduce({}) do |h, action|
12
+ h[action.to_sym] = filters_for_action(action, p)
13
+ h
14
+ end
15
+ else
16
+ {p[:action].to_sym => filters_for_action(p[:action], p)}
17
+ end
18
+ end
19
+
20
+ def before_filters(action = nil)
21
+ filters kind: :before, action: action
22
+ end
23
+
24
+ def around_filters(action = nil)
25
+ filters kind: :around, action: action
26
+ end
27
+
28
+ def after_filters(action = nil)
29
+ filters kind: :after, action: action
30
+ end
31
+
32
+ def filters_for_self_and_descendants(p = {})
33
+ [self.name.to_sym, symbolized_descendants].flatten.reduce({}) do |h, d|
34
+ h[d] = safe_instantiate(d).send(:filters, p)
35
+ h
36
+ end
37
+ end
38
+
39
+ def before_filters_for_self_and_descendants
40
+ filters_for_self_and_descendants({kind: :before})
41
+ end
42
+
43
+ def around_filters_for_self_and_descendants(p = {})
44
+ filters_for_self_and_descendants({kind: :around})
45
+ end
46
+
47
+ def after_filters_for_self_and_descendants
48
+ filters_for_self_and_descendants({kind: :after})
49
+ end
50
+
51
+ # FIXME: what about filters with the same name in different controllers?
52
+ def actions_skipping_filter(filter)
53
+ filters_for_self_and_descendants.reduce({}) do |h, tuple|
54
+ # We want to handle the false positive of someone supplying a filter
55
+ # that simply does not exist either at all, or for the current
56
+ # controller being analyzed.
57
+ if !safe_instantiate(tuple.first).defined_filters.include?(filter)
58
+ puts "Filter #{filter} is not defined for #{tuple.first.to_s}. Skipping."
59
+ h[tuple.first] = []
60
+ else
61
+ h[tuple.first] = tuple.last.keys.select do |action|
62
+ !tuple.last[action].include?(filter.to_sym)
63
+ end
64
+ end
65
+ h
66
+ end.keep_if { |key, val| !val.empty? }
67
+ end
68
+
69
+ # FIXME: what about filters with the same name in different controllers?
70
+ def actions_using_filter(filter)
71
+ filters_for_self_and_descendants.reduce({}) do |h, tuple|
72
+ h[tuple.first] = tuple.last.keys.select do |action|
73
+ tuple.last[action].include?(filter.to_sym)
74
+ end
75
+ h
76
+ end.keep_if { |key, val| !val.empty? }
77
+ end
78
+
79
+ # This is just like action_methods found in the AbstractController class,
80
+ # but we provide the option to not include inherited methods
81
+ def action_methods(include_ans = true)
82
+ methods = super()
83
+ methods & public_instance_methods(false).map(&:to_s) unless include_ans
84
+ end
85
+
86
+ def defined_filters
87
+ @defined_filters ||= filters_for_self.map(&:filter)
88
+ end
89
+
90
+ private
91
+
92
+ def filters_for_self
93
+ @filters_for_self ||= _process_action_callbacks
94
+ end
95
+
96
+ def symbolized_descendants
97
+ @symbolized_descendants ||= symbolize_descendants
98
+ end
99
+
100
+ def filter_for_kind?(filter, kind)
101
+ return true if kind.nil?
102
+ filter.kind == kind
103
+ end
104
+
105
+ def filter_runs_for_action?(filter, action)
106
+ return true if action.nil? or filter.per_key.empty?
107
+ # XXX The @per_key attribute used below builds up its conditionals using
108
+ # action_name as the attribute to compare against. I don't like depending
109
+ # on this, but I don't see any way around it. Just keep this in mind if
110
+ # things ever start breaking.
111
+ action_name = action.to_s
112
+ conditions = ["true"]
113
+ unless filter.per_key[:if].empty?
114
+ conditions << Array.wrap("(#{filter.per_key[:if].first})")
115
+ end
116
+ unless filter.per_key[:unless].empty?
117
+ conditions << Array.wrap("!(#{filter.per_key[:unless].first})")
118
+ end
119
+ # XXX I feel safe using eval because we are only accessing Rails internal
120
+ # stuff, but try to come up with a better way to do this in the future if
121
+ # possible.
122
+ eval conditions.flatten.join(" && ")
123
+ end
124
+
125
+ def filters_for_action(action, p)
126
+ filters_for_self.select do |c|
127
+ filter_for_kind?(c, p[:kind]) and filter_runs_for_action?(c, action)
128
+ end.map(&:filter)
129
+ end
130
+
131
+ def safe_instantiate(klass)
132
+ return self unless is_a_descendant?(klass)
133
+ klass.to_s.constantize
134
+ end
135
+
136
+ def symbolize_descendants
137
+ Rails.application.eager_load! if Rails.env != "production"
138
+ descendants.map do |d|
139
+ d.name.to_sym
140
+ end
141
+ end
142
+
143
+ def is_a_descendant?(klass)
144
+ symbolized_descendants.include?(klass)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,10 @@
1
+ module ActionDebug
2
+ class Railtie < Rails::Railtie
3
+ initializer "actiondebug.action_controller" do
4
+ ActiveSupport.on_load(:action_controller) do
5
+ puts "Extending #{self} with ActionDebug"
6
+ include ActionDebug::Controller
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module ActionDebug
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actiondebug
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Blake Hitchcock
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.5'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! " actiondebug is a utility that can give you more insight\n into
47
+ the structure of your Rails application. It can show all filters that\n a controller
48
+ is using, grouped by action. It can also report which actions\n skip a given
49
+ filter. Its extendability is essentially endless. Great tool\n for security researchers
50
+ and developers alike.\n"
51
+ email:
52
+ - rbhitchcock@gmail.com
53
+ executables: []
54
+ extensions: []
55
+ extra_rdoc_files: []
56
+ files:
57
+ - .gitignore
58
+ - Gemfile
59
+ - LICENSE
60
+ - README.md
61
+ - Rakefile
62
+ - actiondebug.gemspec
63
+ - lib/actiondebug.rb
64
+ - lib/actiondebug/controller.rb
65
+ - lib/actiondebug/railtie.rb
66
+ - lib/actiondebug/version.rb
67
+ homepage: https://github.com/rbhitchcock/actiondebug
68
+ licenses:
69
+ - MIT
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ segments:
81
+ - 0
82
+ hash: 3255717403200248515
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ segments:
90
+ - 0
91
+ hash: 3255717403200248515
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 1.8.24
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: A gem to show which *_filters affect your Rails controllers
98
+ test_files: []