ronin-rb/ronin-exploits

View on GitHub
lib/ronin/exploits/mixins/html.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true
#
# ronin-exploits - A Ruby library for ronin-rb that provides exploitation and
# payload crafting functionality.
#
# Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-exploits is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-exploits is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-exploits.  If not, see <https://www.gnu.org/licenses/>.
#

require 'ronin/support/encoding/html'
require 'ronin/support/text/core_ext'

module Ronin
  module Exploits
    module Mixins
      #
      # Mixin which adds methods for building HTML.
      #
      module HTML
        #
        # Formats an HTML attribute name.
        #
        # @param [String, Symbol] name
        #   The attribute name.
        #
        # @param [:lower, :upper, :random, nil] name_case
        #   Changes the case of the attribute name.
        #
        # @return [String]
        #   The formatted attribute name.
        #
        # @raise [ArgumentError]
        #   An invalid `name_case:` value was given.
        #
        def attr_name(name, name_case: nil)
          name = name.to_s

          case name_case
          when :random then name.random_case
          when :lower  then name.downcase
          when :upper  then name.upcase
          when nil     then name
          else
            raise(ArgumentError,"HTML attr name case (#{name_case.inspect}) was not :lower, :upper, :random, or nil")
          end
        end

        #
        # Formats an HTML attribute.
        #
        # @param [String, Symbol] name
        #   The attribute's name.
        #
        # @param [#to_s] value
        #   The attribute's value.
        #
        # @param [:lower, :upper, :random, nil] name_case
        #   Changes the case of the attribute name.
        #
        # @param [:double, :single, :backtick, nil] quote
        #   Controls how the attribute's value will be quoted.
        #
        # @return [String]
        #   The formatted HTML attribute and value.
        #
        # @raise [ArgumentError]
        #   And invalid `name_case:` or `quote:` value was given.
        #
        def attr(name,value, name_case: nil, quote: :double)
          name  = attr_name(name, name_case: name_case)
          value = Support::Encoding::HTML.escape(value.to_s)

          quoted_value = case quote
                         when :double
                           "\"#{value}\""
                         when :single
                           "'#{value}'"
                         when :backtick
                           "`#{value}`"
                         when nil
                           value.gsub(' ','&nbsp;')
                         else
                           raise(ArgumentError,"quote keyword argument (#{quote.inspect}) was not :double, :single, :backtick, or nil")
                         end

          return "#{name}=#{quoted_value}"
        end

        #
        # Formats an HTML attributes list.
        #
        # @param [Hash{String,Symbol => #to_s}] attrs
        #   The attribute names and values to format.
        #
        # @param [Hash{Symbol => Object}] kwargs
        #   Additional keyword arguments for {#attr}.
        #
        # @option kwargs [:lower, :upper, :random, nil] :name_case
        #   Changes the case of the attribute name.
        #
        # @option kwargs [:double, :single, :backtick, nil] :quote
        #   Controls how the attribute's value will be quoted.
        #
        # @return [String]
        #   The formatted HTML attributes list.
        #
        # @raise [ArgumentError]
        #   And invalid `name_case:` or `quote:` value was given.
        #
        def attr_list(attrs,**kwargs)
          attrs.map { |name,value|
            attr(name,value,**kwargs)
          }.join(' ')
        end

        #
        # Formats an HTML tag name.
        #
        # @param [String, Symbol] name
        #   The tag name.
        #
        # @param [:lower, :upper, :random, nil] name_case
        #   Changes the case of the tag name.
        #
        # @return [String]
        #   The formatted HTML tag.
        #
        # @raise [ArgumentError]
        #   An invalid `name_case:` value was given.
        #
        def tag_name(name, name_case: nil)
          name = name.to_s

          case name_case
          when :random then name.random_case
          when :lower  then name.downcase
          when :upper  then name.upcase
          when nil     then name
          else
            raise(ArgumentError,"HTML tag name case (#{name_case.inspect}) was not :lower, :upper, :random, or nil")
          end
        end

        #
        # Formats an HTML tag.
        #
        # @param [String, Symbol] name
        #   The HTML tag name.
        #
        # @param [:lower, :upper, :random, nil] tag_case
        #   Changes the case of the tag name.
        #
        # @param [:lower, :upper, :random, nil] attr_case
        #   Changes the case of the attribute name.
        #
        # @param [#to_s, nil] text
        #   Optional inner text for the tag.
        #
        # @param [Hash{#to_s => #to_s}] attrs
        #   Additional attributes for the tag.
        #
        # @yield []
        #   If a block is given, it's return value will be used as the tag's
        #   contents. Otherwise, the `text:` value will be used as the tag's
        #   contents.
        #
        # @return [String]
        #   The formatted HTML tag.
        #
        # @raise [ArgumentError]
        #   An invalid `tag_case:` or `attr_case:` value was given.
        #
        # @example
        #   tag('img', src: 'https://example.com/image.jpg')
        #   # => "<img src=\"https://example.com/image.jpg\">"
        #
        # @example with a block:
        #   tag('p', class: 'foo') do
        #     tag('a', href: 'https://example.com/', text: "click me")
        #   end
        #   # => "<p class=\"foo\"><a href=\"https://example.com/\">click me</a></p>"
        #
        def tag(name, tag_case: nil, attr_case: nil, attr_quote: :double, text: nil, **attrs)
          tag_name     = self.tag_name(name, name_case: tag_case)
          tag_contents = if !attrs.empty?
                           attrs = attr_list(attrs, name_case: attr_case,
                                                    quote:     attr_quote)

                           "#{tag_name} #{attrs}"
                         else
                           tag_name
                         end

          if block_given?
            "<#{tag_contents}>#{yield}</#{tag_name}>"
          elsif text
            "<#{tag_contents}>#{text}</#{tag_name}>"
          else
            "<#{tag_contents}/>"
          end
        end
      end
    end
  end
end