lib/kindergarten/governesses/head_governess.rb
module Kindergarten
# The Governess keeps an eye on the child in the sandbox and makes sure
# she plays nicely and within the bounds of legality
#
class HeadGoverness
include CanCan::Ability
attr_reader :child
def initialize(child)
@child = child
@unguarded = false
@rules = []
end
# The governess is empty when no rules have been defined
def empty?
@rules.empty?
end
# Perform a sandbox method within the care of the governess.
#
# The HeadGoverness does nothing with it.
#
# @param [Symbol] method The name of the method that will be executed (for
# logging, record-keeping, raising, etc.)
# @return The result of the block
#
def governed(method, &block)
raise "You must specify a block" unless block_given?
return yield
end
# Check to see if the child can do something, increments @guard_count
#
# @param action Action to take
# @param target On given target
# @param opts [Hash] options
# @option opts [String] :message The message on access denied
#
# @raise [Kindergarten::AccessDenied] when the kindergarten is guarded and
# the action is not allowed
#
# @return The given target to allow
# def project(id)
# project = Project.find(id)
# guard(:view, project)
# end
#
def guard(action, target, opts={})
if guarded? && cannot?(action, target)
raise Kindergarten::AccessDenied.new(action, target, opts)
end
# to allow
# def project(id)
# project = Project.find(id)
# guard(:view, project)
# end
#
return target
end
# When a block is given, set the Governess to unguarded during the
# execution of the block
#
def unguarded(&block)
if block_given?
before = @unguarded
@unguarded = true
yield
@unguarded = before
end
end
def guarded?
!unguarded?
end
def unguarded?
!!@unguarded
end
# Scrub a hash of any key that is not specified
#
# @param [Hash] attributes An attributes-hash to scrub
# @param [Symbol] list A list of allowed attributes
#
# @return [ScrubbedHash] a hash with only allowed keys
def scrub(attributes, *list)
list.map!(&:to_sym)
if attributes.respond_to?(:symbolize_keys!)
attributes.symbolize_keys!
else
attributes = attributes.symbolize_keys
end
forbidden = Kindergarten::Governesses.forbidden_keys
Kindergarten::ScrubbedHash[
attributes.delete_if do |key,value|
forbidden.include?(key) || !list.include?(key)
end
]
end
# Scrub a hash of any key that is not specified
#
# @param [Hash] attributes An attributes-hash to scrub
# @param [Hash] untaint_opts Specify a Regexp for each key. The value from
# the attributes will be matched against the regexp and replaced with
# the first result.
#
# specify :pass instead of a Regexp to let the value pass without
# matching (usefull for non strings, etc.)
#
# @return [RinsedHash] a hash with only allowed keys and untainted values
#
# @example Untaint
# rinse(attributes, :name => /^([a-Z0-9]+)/, :description => /([\w\s-]+)/mg)
#
# @example Pass on a Date attribute
# rinse(attributes, :name => /([\w\s-]+)/, :date => :pass)
#
# @example Bad practice
# # beware of the dot-star!
# rinse(attributes, :name => /(.*)/)
#
def rinse(attributes, untaint_opts)
untaint_opts.symbolize_keys!
scrubbed = scrub(attributes, *untaint_opts.keys)
scrubbed.each do |key, value|
untaint = untaint_opts[key]
next if untaint == :pass
match = "#{value}".match(untaint)
if match.nil?
scrubbed.delete key
else
scrubbed[key] = match[1]
end
end
return Kindergarten::RinsedHash[scrubbed]
end
end
end