Remove untainting in preparation for Ruby 3.
M README.rdoc +1 -1
@@ 216,7 216,7 @@ and generate the API documentation.
 
 == License
 
-Copyright (c) 2011-2019, Michael Granger and Mahlon E. Smith
+Copyright (c) 2011-2020, Michael Granger and Mahlon E. Smith
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without

          
M gem.deps.rb +3 -2
@@ 4,7 4,7 @@ gem 'configurability', '~> 3.1'
 gem 'foreman', '~> 0.62'
 gem 'highline', '~> 1.6'
 gem 'inversion', '~> 1.0'
-gem 'loggability', '~> 0.9'
+gem 'loggability', '~> 0.15'
 gem 'mongrel2', '~> 0.53'
 gem 'pluggability', '~> 0.4'
 gem 'sysexits', '~> 1.1'

          
@@ 13,9 13,10 @@ gem 'safe_yaml', '~> 1.0'
 gem 'gli', '~> 2.14'
 
 group( :development ) do
-	gem 'rake-deveiate', '~> 0.4'
+	gem 'rake-deveiate', '~> 0.5'
 	gem 'rspec', '~> 3.8'
 	gem 'simplecov', '~> 0.7'
 	gem 'rdoc-generator-fivefish', '~> 0.1'
+	gem 'sqlite3', '~> 1.4', '>= 1.4.2'
 end
 

          
M lib/strelka/app/parameters.rb +3 -12
@@ 8,11 8,10 @@ require 'strelka/plugins'
 require 'strelka/paramvalidator'
 
 
-# Parameter validation and untainting for Strelka apps.
+# Parameter validation for Strelka apps.
 #
-# When you include the +:parameters+ plugin, you can declare valid parameters, specify
-# constraints that describe what they should contain, and automatically untaint the incoming
-# values that match.
+# When you include the +:parameters+ plugin, you can declare valid parameters and specify
+# constraints that describe what incoming values should match.
 #
 # == Parameter Declaration
 #

          
@@ 101,14 100,6 @@ module Strelka::App::Parameters
 		end
 
 
-		### Get/set the untainting flag. If set, all parameters which match their constraints
-		### will also be untainted.
-		def untaint_all_constraints( newval=nil )
-			self.paramvalidator.untaint_all = newval unless newval.nil?
-			return self.paramvalidator.untaint_all?
-		end
-
-
 		### Inheritance hook -- inheriting classes inherit their parents' parameter
 		### declarations, too.
 		def inherited( subclass )

          
M lib/strelka/app/restresources.rb +0 -3
@@ 152,9 152,6 @@ module Strelka::App::RestResources
 			route = [ options[:prefix], name ].compact.join( '/' )
 			self.log.warn "Route is: %p" % [[ options[:prefix], name ]]
 
-			# Ensure validated parameters are untainted
-			self.untaint_all_constraints
-
 			# Make and install handler methods
 			self.log.debug "  adding readers"
 			self.add_options_handler( route, rsrcobj, options )

          
M lib/strelka/cookie.rb +1 -1
@@ 79,7 79,7 @@ class Strelka::Cookie
 				raise Strelka::ParseError, "malformed cookie pair: %p" % [ cookie_pair ]
 
 			# self.log.debug "  matched cookie: %p" % [ match ]
-			name = match[:cookie_name].untaint
+			name = match[:cookie_name]
 			value = match[:cookie_value]
 			value = self.dequote( value ) if value.start_with?( DQUOTE )
 			value = nil if value.empty?

          
M lib/strelka/mixins.rb +1 -1
@@ 244,7 244,7 @@ module Strelka
 			newhash = {}
 
 			hash.each do |key,val|
-				keysym = key.to_s.dup.untaint.to_sym
+				keysym = key.to_s.dup.to_sym
 
 				if val.is_a?( Hash )
 					newhash[ keysym ] = symbolify_keys( val )

          
M lib/strelka/paramvalidator.rb +22 -45
@@ 26,10 26,7 @@ require 'strelka/app' unless defined?( S
 #	validator.add( :feedback, :printable, "Customer Feedback" )
 #	validator.override( :email, :printable, "Your Email Address" )
 #
-#	# Untaint all parameter values which match their constraints
-#	validate.untaint_all_constraints = true
-#
-#	# Now pass in tainted values in a hash (e.g., from an HTML form)
+#	# Now pass in values in a hash (e.g., from an HTML form)
 #	validator.validate( req.params )
 #
 #	# Now if there weren't any errors, use some form values to fill out the

          
@@ 79,7 76,7 @@ class Strelka::ParamValidator
 
 
 		# Flags that are passed as Symbols when declaring a parameter
-		FLAGS = [ :required, :untaint, :multiple ]
+		FLAGS = [ :required, :multiple ]
 
 		# Map of constraint specification types to their equivalent Constraint class.
 		TYPES = { Proc => self }

          
@@ 124,7 121,6 @@ class Strelka::ParamValidator
 			@description = args.shift if args.first.is_a?( String )
 
 			@required	 = args.include?( :required )
-			@untaint	 = args.include?( :untaint )
 			@multiple	 = args.include?( :multiple )
 		end
 

          
@@ 151,19 147,13 @@ class Strelka::ParamValidator
 		# order for the parameters to be valid.
 		attr_predicate :required?
 
-		##
-		# Returns true if the constraint will also untaint its result before returning it.
-		attr_predicate :untaint?
-
 
 		### Check the given value against the constraint and return the result if it passes.
-		def apply( value, force_untaint=false )
-			untaint = self.untaint? || force_untaint
-
+		def apply( value )
 			if self.multiple?
-				return self.check_multiple( value, untaint )
+				return self.check_multiple( value )
 			else
-				return self.check( value, untaint )
+				return self.check( value )
 			end
 		end
 

          
@@ 190,7 180,6 @@ class Strelka::ParamValidator
 			flags = []
 			flags << 'required' if self.required?
 			flags << 'multiple' if self.multiple?
-			flags << 'untaint' if self.untaint?
 
 			desc << " (%s)" % [ flags.join(',') ] unless flags.empty?
 

          
@@ 218,21 207,20 @@ class Strelka::ParamValidator
 		### Check the specified value against the constraint and return the results. By
 		### default, this just calls to_proc and the block and calls the result with the
 		### value as its argument.
-		def check( value, untaint )
+		def check( value )
 			return self.block.to_proc.call( value ) if self.block
-			value.untaint if untaint && value.respond_to?( :untaint )
 			return value
 		end
 
 
 		### Check the given +values+ against the constraint and return the results if
 		### all of them succeed.
-		def check_multiple( values, untaint )
+		def check_multiple( values )
 			values = [ values ] unless values.is_a?( Array )
 			results = []
 
 			values.each do |value|
-				result = self.check( value, untaint ) or return nil
+				result = self.check( value ) or return nil
 				results << result
 			end
 

          
@@ 280,38 268,35 @@ class Strelka::ParamValidator
 
 		### Check the +value+ against the regular expression and return its
 		### match groups if successful.
-		def check( value, untaint )
+		def check( value )
 			self.log.debug "Validating %p via regexp %p" % [ value, self.pattern ]
 			match = self.pattern.match( value.to_s ) or return nil
 
 			if match.captures.empty?
 				self.log.debug "  no captures, using whole match: %p" % [match[0]]
-				return super( match[0], untaint )
+				return super( match[0] )
 
 			elsif match.names.length > 1
 				self.log.debug "  extracting hash of named captures: %p" % [ match.names ]
-				rhash = self.matched_hash( match, untaint )
-				return super( rhash, untaint )
+				rhash = self.matched_hash( match )
+				return super( rhash )
 
 			elsif match.captures.length == 1
 				self.log.debug "  extracting one capture: %p" % [match.captures.first]
-				return super( match.captures.first, untaint )
+				return super( match.captures.first )
 
 			else
 				self.log.debug "  extracting multiple captures: %p" % [match.captures]
 				values = match.captures
-				values.map {|val| val.untaint if val } if untaint
-				return super( values, untaint )
+				return super( values )
 			end
 		end
 
 
-		### Return a Hash of the given +match+ object's named captures, untainting the values
-		### if +untaint+ is true.
-		def matched_hash( match, untaint )
+		### Return a Hash of the given +match+ object's named captures.
+		def matched_hash( match )
 			return match.names.inject( {} ) do |accum,name|
 				value = match[ name ]
-				value.untaint if untaint && value
 				accum[ name.to_sym ] = value
 				accum
 			end

          
@@ 566,7 551,6 @@ class Strelka::ParamValidator
 	def initialize
 		@constraints = {}
 		@fields      = {}
-		@untaint_all = false
 
 		self.reset
 	end

          
@@ 592,12 576,6 @@ class Strelka::ParamValidator
 	attr_reader :fields
 
 	##
-	# Global untainting flag
-	attr_predicate_accessor :untaint_all?
-	alias_method :untaint_all_constraints=, :untaint_all=
-	alias_method :untaint_all_constraints?, :untaint_all?
-
-	##
 	# Returns +true+ if the paramvalidator has been given parameters to validate. Adding or
 	# overriding constraints resets this.
 	attr_predicate_accessor :validated?

          
@@ 680,13 658,12 @@ class Strelka::ParamValidator
 			constraint.required?
 		end
 
-		return "#<%p:0x%016x %s, profile: [required: %s, optional: %s] global untaint: %s>" % [
+		return "#<%p:0x%016x %s, profile: [required: %s, optional: %s]>" % [
 			self.class,
 			self.object_id / 2,
 			self.to_s,
 			required.empty? ? "(none)" : required.map( &:last ).map( &:name ).join(','),
 			optional.empty? ? "(none)" : optional.map( &:last ).map( &:name ).join(','),
-			self.untaint_all? ? "enabled" : "disabled",
 		]
 	end
 

          
@@ 754,7 731,7 @@ class Strelka::ParamValidator
 	### result.
 	def apply_constraint( constraint, value )
 		if !( value.nil? || value == '' )
-			result = constraint.apply( value, self.untaint_all? )
+			result = constraint.apply( value )
 
 			if !result.nil?
 				self.log.debug "  constraint for %p passed: %p" % [ constraint.name, result ]

          
@@ 976,7 953,7 @@ class Strelka::ParamValidator
 	### Build a deep hash out of the given parameter +value+
 	def build_deep_hash( value, hash, levels )
 		if levels.length == 0
-			value.untaint
+			value
 		elsif hash.nil?
 			{ levels.first => build_deep_hash(value, nil, levels[1..-1]) }
 		else

          
@@ 992,11 969,11 @@ class Strelka::ParamValidator
 		if main.nil?
 			return []
 		elsif trailing
-			return [key.untaint]
+			return [key]
 		elsif bracketed
-			return [main.untaint] + bracketed.slice(1...-1).split('][').collect {|k| k.untaint }
+			return [main] + bracketed.slice(1...-1).split('][')
 		else
-			return [main.untaint]
+			return [main]
 		end
 	end
 

          
M lib/strelka/session/default.rb +1 -1
@@ 78,7 78,7 @@ class Strelka::Session::Default < Strelk
 		cookie = request.cookies[ self.cookie_name ] or return nil
 
 		if cookie.value =~ /^([[:xdigit:]]+)$/i
-			return $1.untaint
+			return $1
 		else
 			self.log.warn "Request with a malformed session cookie: %p" % [ request ]
 			return nil

          
M spec/strelka/app/parameters_spec.rb +1 -27
@@ 119,39 119,13 @@ RSpec.describe Strelka::App::Parameters 
 			end
 
 			it "validates parameters from the request" do
-				req = @request_factory.get( (+'/user/search?username=anheptoh').taint )
+				req = @request_factory.get( (+'/user/search?username=anheptoh') )
 				@app.new.handle( req )
 
 				expect( req.params ).to be_a( Strelka::ParamValidator )
 				expect( req.params ).to be_okay()
 				expect( req.params ).to_not have_errors()
 				expect( req.params[:username] ).to eq( 'anheptoh' )
-				expect( req.params[:username] ).to be_tainted()
-			end
-
-			it "untaints all parameters if global untainting is enabled" do
-				@app.class_eval do
-					untaint_all_constraints true
-				end
-
-				expect( @app.untaint_all_constraints ).to be_truthy()
-				req = @request_factory.get( (+'/user/search?username=shereshnaheth').taint )
-				@app.new.handle( req )
-
-				expect( req.params[:username] ).to eq( 'shereshnaheth' )
-				expect( req.params[:username] ).to_not be_tainted()
-			end
-
-			it "untaints parameters flagged for untainting" do
-				@app.class_eval do
-					param :message, :printable, :untaint
-				end
-
-				req = @request_factory.get( (+'/user/search?message=I+love+the+circus.').taint )
-				@app.new.handle( req )
-
-				expect( req.params[:message] ).to_not be_tainted()
-				expect( req.params[:message] ).to eq( 'I love the circus.' )
 			end
 
 		end

          
M spec/strelka/mixins_spec.rb +0 -10
@@ 279,16 279,6 @@ RSpec.describe Strelka, "mixins" do
 			expect( copy.default_proc ).to eq( original.default_proc )
 		end
 
-		it "preserves taintedness of copied objects" do
-			original = Object.new
-			original.taint
-
-			copy = Strelka::DataUtilities.deep_copy( original )
-
-			expect( copy ).to_not be( original )
-			expect( copy ).to be_tainted()
-		end
-
 		it "preserves frozen-ness of copied objects" do
 			original = Object.new
 			original.freeze

          
M spec/strelka/paramvalidator_spec.rb +4 -54
@@ 16,12 16,6 @@ require 'strelka/paramvalidator'
 #####################################################################
 RSpec.describe Strelka::ParamValidator do
 
-	# Utility function to make tainted frozen strings out of frozen string literals
-	def tainted( string )
-		return ( +string ).taint.freeze
-	end
-
-
 	before(:each) do
 		@validator = Strelka::ParamValidator.new
 	end

          
@@ 138,16 132,6 @@ RSpec.describe Strelka::ParamValidator d
 			expect( @validator.error_messages.first ).to match( /foo/i )
 		end
 
-		it "untaints valid args if told to do so" do
-			tainted_one = tainted( "1" )
-
-			@validator.add( :number, /^\d+$/, :untaint )
-			@validator.validate( 'number' => tainted_one )
-
-			expect( @validator[:number] ).to eq( "1" )
-			expect( @validator[:number].tainted? ).to be_falsey()
-		end
-
 		it "knows the names of fields that were required but missing from the parameters" do
 			@validator.add( :id, :integer, :required )
 			@validator.validate( {} )

          
@@ 340,38 324,6 @@ RSpec.describe Strelka::ParamValidator d
 			})
 		end
 
-		it "untaints both keys and values in complex hash fields if untainting is turned on" do
-			@validator.add( 'recipe[ingredient][rarity]', /^([\w\-]+)$/, :required )
-			@validator.add( 'recipe[ingredient][name]', :string )
-			@validator.add( 'recipe[ingredient][cost]', :string )
-			@validator.add( 'recipe[yield]', :string )
-			@validator.untaint_all_constraints = true
-
-			args = {
-				tainted('recipe[ingredient][rarity]') => tainted('super-rare'),
-				tainted('recipe[ingredient][name]') => tainted('nutmeg'),
-				tainted('recipe[ingredient][cost]') => tainted('$0.18'),
-				tainted('recipe[yield]') => tainted('2 loaves'),
-			}
-			@validator.validate( args )
-
-			expect( @validator.valid ).to eq({
-				'recipe' => {
-					'ingredient' => { 'name' => 'nutmeg', 'cost' => '$0.18', 'rarity' => 'super-rare' },
-					'yield' => '2 loaves'
-				}
-			})
-
-			@validator.valid.keys.each {|key| expect(key).to_not be_tainted() }
-			@validator.valid.values.each {|key| expect(key).to_not be_tainted() }
-			@validator.valid['recipe'].keys.each {|key| expect(key).to_not be_tainted() }
-			@validator.valid['recipe']['ingredient'].keys.each {|key| expect(key).to_not be_tainted() }
-			expect( @validator.valid['recipe']['yield'] ).to_not be_tainted()
-			expect( @validator.valid['recipe']['ingredient']['rarity'] ).to_not be_tainted()
-			expect( @validator.valid['recipe']['ingredient']['name'] ).to_not be_tainted()
-			expect( @validator.valid['recipe']['ingredient']['cost'] ).to_not be_tainted()
-		end
-
 	end # describe "hash parameters"
 
 	describe "merging new parameters" do

          
@@ 453,12 405,10 @@ RSpec.describe Strelka::ParamValidator d
 			end
 
 			it "returns the captures with named captures as a Hash" do
-				@validator.add( :order_number, /(?<category>[[:upper:]]{3})-(?<sku>\d{12})/, :untaint )
-				@validator.validate( 'order_number' => tainted("   JVV-886451300133   ") )
+				@validator.add( :order_number, /(?<category>[[:upper:]]{3})-(?<sku>\d{12})/ )
+				@validator.validate( 'order_number' => "   JVV-886451300133   ".dup )
 
 				expect( @validator[:order_number] ).to eq( {:category => 'JVV', :sku => '886451300133'} )
-				expect( @validator[:order_number][:category] ).to_not be_tainted()
-				expect( @validator[:order_number][:sku] ).to_not be_tainted()
 			end
 
 			it "returns the captures as an array " +

          
@@ 782,7 732,7 @@ RSpec.describe Strelka::ParamValidator d
 
 		end
 
-		describe ":date constaints" do
+		describe ":date constraints" do
 
 			before( :each ) do
 				@validator.add( :expires, :date )

          
@@ 808,7 758,7 @@ RSpec.describe Strelka::ParamValidator d
 
 		end
 
-		describe ":datetime constaints" do
+		describe ":datetime constraints" do
 
 			before( :each ) do
 				@validator.add( :expires, :datetime )