module BetterHtml class BetterErb class ValidatedOutputBuffer def self.wrap(output, context, code, auto_escape) Context.new(output, context, code, auto_escape) end class Context def initialize(output, context, code, auto_escape) @output = output @context = context @code = code @auto_escape = auto_escape end def safe_quoted_value_append=(value) return if value.nil? value = properly_escaped(value) if value.include?(@context[:quote_character]) raise UnsafeHtmlError, "Detected invalid characters as part of the interpolation "\ "into a quoted attribute value. The value cannot contain the character #{@context[:quote_character]}." end @output.safe_append= value end def safe_unquoted_value_append=(value) raise DontInterpolateHere, "Do not interpolate without quotes around this "\ "attribute value. Instead of "\ "<#{@context[:tag_name]} #{@context[:attribute_name]}=#{@context[:attribute_value]}<%=#{@code}%>> "\ "try <#{@context[:tag_name]} #{@context[:attribute_name]}=\"#{@context[:attribute_value]}<%=#{@code}%>\">." end def safe_space_after_attribute_append=(value) raise DontInterpolateHere, "Add a space after this attribute value. Instead of "\ "<#{@context[:tag_name]} #{@context[:attribute_name]}=\"#{@context[:attribute_value]}\"<%=#{@code}%>> "\ "try <#{@context[:tag_name]} #{@context[:attribute_name]}=\"#{@context[:attribute_value]}\" <%=#{@code}%>>." end def safe_attribute_name_append=(value) return if value.nil? value = value.to_s unless value =~ /\A[a-z0-9\-]*\z/ raise UnsafeHtmlError, "Detected invalid characters as part of the interpolation "\ "into a attribute name around '#{@context[:attribute_name]}<%=#{@code}%>'." end @output.safe_append= value end def safe_after_attribute_name_append=(value) return if value.nil? unless value.is_a?(BetterHtml::HtmlAttributes) raise DontInterpolateHere, "Do not interpolate #{value.class} in a tag. "\ "Instead of <#{@context[:tag_name]} <%=#{@code}%>> please "\ "try <#{@context[:tag_name]} <%= html_attributes(attr: value) %>>." end @output.safe_append= value.to_s end def safe_after_equal_append=(value) raise DontInterpolateHere, "Do not interpolate without quotes after "\ "attribute around '#{@context[:attribute_name]}=<%=#{@code}%>'." end def safe_tag_append=(value) return if value.nil? unless value.is_a?(BetterHtml::HtmlAttributes) raise DontInterpolateHere, "Do not interpolate #{value.class} in a tag. "\ "Instead of <#{@context[:tag_name]} <%=#{@code}%>> please "\ "try <#{@context[:tag_name]} <%= html_attributes(attr: value) %>>." end @output.safe_append= value.to_s end def safe_tag_name_append=(value) return if value.nil? value = value.to_s unless value =~ /\A[a-z0-9\:\-]*\z/ raise UnsafeHtmlError, "Detected invalid characters as part of the interpolation "\ "into a tag name around: <#{@context[:tag_name]}<%=#{@code}%>>." end @output.safe_append= value end def safe_rawtext_append=(value) return if value.nil? value = properly_escaped(value) if @context[:tag_name].downcase == 'script' && (value =~ /#{@context[:rawtext_text]}<%=#{@code}%>." end @output.safe_append= value end def safe_comment_append=(value) return if value.nil? value = properly_escaped(value) # in a we disallow --> if value =~ /-->/ raise UnsafeHtmlError, "Detected invalid characters as part of the interpolation "\ "into a html comment around: