# 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 .
#
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(' ',' ')
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')
# # => ""
#
# @example with a block:
# tag('p', class: 'foo') do
# tag('a', href: 'https://example.com/', text: "click me")
# end
# # => "
click me
"
#
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