class Ronin::Support::Network::EmailAddress

Represents an email address.

## Features

## Examples

Builds a new email address:

email = EmailAddress.new(mailbox: 'john.smith', domain: 'example.com')

Parses an email address:

email = EmailAddress.parse("John Smith <john.smith@example.com>")
# => #<Ronin::Support::Network::EmailAddress:0x00007f49586d6a20
      @address=nil,
      @domain="example.com",
      @mailbox="john.smith",
      @name="John Smith",
      @routing=nil,
      @tag=nil>

Deobfuscate an obfuscated email address:

EmailAddress.deobfuscate("john[dot]smith [at] example[dot]com")
# => "john.smith@example.com"

Obfuscate an email address:

email = EmailAddress.parse("john.smith@example.com")
email.obfuscate
# => "john <dot> smith <at> example <dot> com"

Get every obfuscation of an email address:

email.obfuscations
# => ["john.smith AT example.com",
#     "john.smith at example.com",
#     "john.smith[AT]example.com",
#     "john.smith[at]example.com",
#     "john.smith [AT] example.com",
#     "john.smith [at] example.com",
#     "john.smith<AT>example.com",
#     "john.smith<at>example.com",
#     "john.smith <AT> example.com",
#     "john.smith <at> example.com",
#     "john.smith{AT}example.com",
#     "john.smith{at}example.com",
#     "john.smith {AT} example.com",
#     "john.smith {at} example.com",
#     "john.smith(AT)example.com",
#     "john.smith(at)example.com",
#     "john.smith (AT) example.com",
#     "john.smith (at) example.com",
#     "john DOT smith AT example DOT com",
#     "john dot smith at example dot com",
#     "john[DOT]smith[AT]example[DOT]com",
#     "john[dot]smith[at]example[dot]com",
#     "john [DOT] smith [AT] example [DOT] com",
#     "john [dot] smith [at] example [dot] com",
#     "john<DOT>smith<AT>example<DOT>com",
#     "john<dot>smith<at>example<dot>com",
#     "john <DOT> smith <AT> example <DOT> com",
#     "john <dot> smith <at> example <dot> com",
#     "john{DOT}smith{AT}example{DOT}com",
#     "john{dot}smith{at}example{dot}com",
#     "john {DOT} smith {AT} example {DOT} com",
#     "john {dot} smith {at} example {dot} com",
#     "john(DOT)smith(AT)example(DOT)com",
#     "john(dot)smith(at)example(dot)com",
#     "john (DOT) smith (AT) example (DOT) com",
#     "john (dot) smith (at) example (dot) com"]

@see datatracker.ietf.org/doc/html/rfc2822#section-3.4

@api public

@since 1.0.0

Constants

DEOBFUSCATIONS

Email address de-obfuscation rules.

OBFUSCATIONS

Email address obfuscation rules.

Attributes

address[R]

The IP address of the email address (ex: ‘john.smith@`).

@return [String, nil]

domain[R]

The domain of the email address (ex: ‘john.smith@example.com`).

@return [String, nil]

mailbox[R]

The mailbox or username of the email address.

@return [String]

name[R]

The optional name associated with the email address (ex: ‘John Smith <john.smith@example.com`).

@return [String, nil]

routing[R]

Additional hosts to route sent emails through; aka the “percent hack” (ex: ‘john.smith%host3.com%host2.com@host1.com`).

@return [Array<String>, nil]

tag[R]

The optional sorting tag of the email address (ex: ‘john.smith+tag@example.com`).

@return [String, nil]

username[R]

The mailbox or username of the email address.

@return [String]

Public Class Methods

deobfuscate(string) click to toggle source

Deobfuscates an obfuscated email address.

@param [String] string

The obfuscated email address to deobfuscate.

@return [String]

The deobfuscated email address.

@example

EmailAddress.deobfuscate("john[dot]smith [at] example[dot]com")
# => "john.smith@example.com"
# File lib/ronin/support/network/email_address.rb, line 355
def self.deobfuscate(string)
  DEOBFUSCATIONS.each do |pattern,replace|
    string = string.gsub(pattern,replace)
  end

  return string
end
new(name: nil, mailbox: , tag: nil, routing: nil, domain: nil, address: nil) click to toggle source

Initializes the email address.

@param [String, nil] name

The optional name associated with the email address
(ex: `John Smith <john.smith@example.com`).

@param [String] mailbox

The mailbox or username of the email address.

@param [String, nil] tag

The optional sorting tag of the email address
(ex: `john.smith+tag@example.com`).

@param [Array<String>, nil] routing

Additional hosts to route sent emails through; aka the
"percent hack" (ex: `john.smith%host3.com%host2.com@host1.com`).

@param [String, nil] domain

The domain of the email address (ex: `john.smith@example.com`).

@param [String, nil] address

The IP address of the email address (ex: `john.smith@[1.2.3.4]`).

@raise [ArgumentError]

Must specify either the `domain:` or `address:` keyword arguments.

@example Initializing a basic email address.

email = EmailAddress.new(mailbox: 'john.smith', domain: 'example.com')

@example Initializing an email address with a name:

email = EmailAddress.new(name: 'John Smith', mailbox: 'john.smith', domain: 'example.com')

@example Initializing an email address with a sorting tag:

email = EmailAddress.new(mailbox: 'john.smith', tag: 'spam', domain: 'example.com')
# File lib/ronin/support/network/email_address.rb, line 180
def initialize(name: nil, mailbox: , tag: nil, routing: nil, domain: nil, address: nil)
  @name    = name
  @mailbox = mailbox
  @tag     = tag
  @routing = routing

  unless (domain.nil? ^ address.nil?)
    raise(ArgumentError,"must specify domain: or address: keyword arguments")
  end

  @domain  = domain
  @address = address
end
parse(string) click to toggle source

Parses an email address.

@param [String] string

The email string to parse.

@return [EmailAddress]

The parsed email address.

@raise [InvalidEmailAddress]

The string is not a valid formatted email address.

@example

email = EmailAddress.parse("John Smith <john.smith@example.com>")
# => #<Ronin::Support::Network::EmailAddress:0x00007f49586d6a20
      @address=nil,
      @domain="example.com",
      @mailbox="john.smith",
      @name="John Smith",
      @routing=nil,
      @tag=nil>

@see datatracker.ietf.org/doc/html/rfc2822#section-3.4

# File lib/ronin/support/network/email_address.rb, line 218
def self.parse(string)
  if string.include?('<') && string.end_with?('>')
    # Name <local-part@domain.com>
    if (match = string.match(/^([^<]+)\s+<([^>]+)>$/))
      name    = match[1]
      address = match[2]
    else
      raise(InvalidEmailAddress,"invalid email address: #{string.inspect}")
    end
  else
    name    = nil
    address = string
  end

  return new(name: name, **parse_address(address))
end
parse_address(string) click to toggle source

Parses the address portion of an email address.

@param [String] string

the email address string to parse.

@return [Hash{Symbol => Object}]

Keyword arguments for {#initialize}.

@raise [InvalidEmailAddress]

The string did not contain a `@` character.

@api private

# File lib/ronin/support/network/email_address.rb, line 249
def self.parse_address(string)
  unless string.include?('@')
    raise(InvalidEmailAddress,"invalid email address: #{string.inspect}")
  end

  # local-part@domain.com
  local_part, domain = string.split('@',2)

  return {**parse_local_part(local_part), **parse_domain(domain)}
end
parse_domain(string) click to toggle source

Parses the domain portion of an email address.

@param [String] string

The domain portion to parse.

@return [Hash{Symbol => Object}]

Keyword arguments for {#initialize}.

@api private

# File lib/ronin/support/network/email_address.rb, line 313
def self.parse_domain(string)
  domain  = nil
  address = nil

  # extract IP addresses from the domain part (ex: `user@[1.2.3.4]`)
  if string.start_with?('[') && string.end_with?(']')
    address = string[1..-2]
  else
    domain  = string
  end

  return {domain: domain, address: address}
end
parse_local_part(string) click to toggle source

Parses the local-part portion of an email address.

@param [String] string

the local-part string to parse.

@return [Hash{Symbol => Object}]

Keyword arguments for {#initialize}.

@api private

# File lib/ronin/support/network/email_address.rb, line 271
def self.parse_local_part(string)
  routing = nil

  if string.include?('%')
    mailbox, *routing = string.split('%')
  else
    mailbox = string
    routing = nil
  end

  return {routing: routing, **parse_mailbox(mailbox)}
end
parse_mailbox(string) click to toggle source

Parses the mailbox portion of an email address.

@param [String] string

The mailbox string to parse.

@return [Hash{Symbol => Object}]

Keyword arguments for {#initialize}.

@api private

# File lib/ronin/support/network/email_address.rb, line 295
def self.parse_mailbox(string)
  # extract any sorting-tags (ex: `user+service@domain.com`)
  mailbox, tag = string.split('+',2)

  return {mailbox: mailbox, tag: tag}
end

Public Instance Methods

each_obfuscation() { |gsub(*gsub_args)| ... } click to toggle source

Enumerates over each obfuscation of the email address.

@yield [obfuscated]

If a block is given, it will be passed every obfuscation of the
email address.

@yieldparam [String] obfuscated

An obfuscated version of the email address.

@return [Enumerator]

If no block is given, an Enumerator will be returned.

@example

email = EmailAddress.parse("john.smith@example.com")
email.each_obfuscation { |obfuscated_email| ... }

@see OBFUSCATIONS

# File lib/ronin/support/network/email_address.rb, line 503
def each_obfuscation
  return enum_for(__method__) unless block_given?

  string = to_s

  OBFUSCATIONS.each do |gsub_args|
    yield string.gsub(*gsub_args)
  end

  return nil
end
hostname() click to toggle source

The hostname to connect to.

@return [String]

The {#domain} or {#address}.
# File lib/ronin/support/network/email_address.rb, line 389
def hostname
  @domain || @address
end
normalize() click to toggle source

Creates a new email address without the {#tag} or {#routing} attribute.

@return [EmailAddress]

The new normalized email address object.

@example

email = EmailAddress.parse("John Smith <john.smith+spam@example.com>")
email.normalize.to_s
# => "john.smith@example.com"
# File lib/ronin/support/network/email_address.rb, line 375
def normalize
  EmailAddress.new(
    mailbox: mailbox,
    domain:  domain,
    address: address
  )
end
obfuscate() click to toggle source

Obfuscates the email address.

@return [String]

A randomly obfuscated version of the email address.

@see OBFUSCATIONS

@example

email = EmailAddress.parse("john.smith@example.com")
email.obfuscate
# => "john.smith [AT] example.com"
email.obfuscate
# => "john <dot> smith <at> example <dot> com"
# File lib/ronin/support/network/email_address.rb, line 478
def obfuscate
  string = to_s
  string.gsub!(*OBFUSCATIONS.sample)
  return string
end
obfuscations() click to toggle source

Returns every obfuscation of the email address.

@return [Array<String>]

The Array containing every obfuscation of the email address.

@example

email = EmailAddress.parse("john.smith@example.com")
email.obfuscations
# => ["john.smith AT example.com",
#     "john.smith at example.com",
#     "john.smith[AT]example.com",
#     "john.smith[at]example.com",
#     "john.smith [AT] example.com",
#     "john.smith [at] example.com",
#     "john.smith<AT>example.com",
#     "john.smith<at>example.com",
#     "john.smith <AT> example.com",
#     "john.smith <at> example.com",
#     "john.smith{AT}example.com",
#     "john.smith{at}example.com",
#     "john.smith {AT} example.com",
#     "john.smith {at} example.com",
#     "john.smith(AT)example.com",
#     "john.smith(at)example.com",
#     "john.smith (AT) example.com",
#     "john.smith (at) example.com",
#     "john DOT smith AT example DOT com",
#     "john dot smith at example dot com",
#     "john[DOT]smith[AT]example[DOT]com",
#     "john[dot]smith[at]example[dot]com",
#     "john [DOT] smith [AT] example [DOT] com",
#     "john [dot] smith [at] example [dot] com",
#     "john<DOT>smith<AT>example<DOT>com",
#     "john<dot>smith<at>example<dot>com",
#     "john <DOT> smith <AT> example <DOT> com",
#     "john <dot> smith <at> example <dot> com",
#     "john{DOT}smith{AT}example{DOT}com",
#     "john{dot}smith{at}example{dot}com",
#     "john {DOT} smith {AT} example {DOT} com",
#     "john {dot} smith {at} example {dot} com",
#     "john(DOT)smith(AT)example(DOT)com",
#     "john(dot)smith(at)example(dot)com",
#     "john (DOT) smith (AT) example (DOT) com",
#     "john (dot) smith (at) example (dot) com"]

@see each_obfuscation

# File lib/ronin/support/network/email_address.rb, line 563
def obfuscations
  each_obfuscation.to_a
end
to_s() click to toggle source

Converts the email address back into a string.

@return [String]

The string representation of the email address.

@example

email = EmailAddress.parse("John Smith <john.smith+spam@example.com>")
email.to_s
# => "John Smith <john.smith+spam@example.com>"
# File lib/ronin/support/network/email_address.rb, line 404
def to_s
  string = "#{@mailbox}"
  string << "+#{@tag}"               if @tag
  string << "%#{@routing.join('%')}" if @routing
  string << "@"
  string << if @address then "[#{@address}]"
            else             @domain
            end
  string = "#{@name} <#{string}>" if @name
  return string
end
Also aliased as: to_str
to_str()
Alias for: to_s