#
# Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# This file is part of Ronin.
#
# Ronin is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ronin 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ronin. If not, see .
#
require 'ronin/extensions/regexp'
require 'ronin/model'
require 'ronin/model/importable'
require 'ronin/user_name'
require 'ronin/host_name'
require 'uri/mailto'
require 'dm-timestamps'
module Ronin
#
# Represents email addresses that can be stored in the {Database}.
#
class EmailAddress
include Model
# The primary key of the email address.
property :id, Serial
# The user-name component of the email address.
belongs_to :user_name
# The host-name component of the email address.
belongs_to :host_name
# Any IP addresses associated with the host name.
has 0..n, :ip_addresses, :through => :host_name,
:model => 'IPAddress'
# Any web credentials that are associated with the email address.
has 0..n, :credentials
# Tracks when the email address was created at.
timestamps :created_at
# Validates the uniqueness of the user-name and the host-name.
validates_uniqueness_of :user_name, :scope => [:host_name]
#
# Extracts email addresses from the given text.
#
# @param [String] text
# The text to parse.
#
# @yield [email]
# The given block will be passed each extracted email address.
#
# @yieldparam [EmailAddress] email
# An extracted host-name.
#
# @return [Array]
# If no block is given, an Array of email address will be returned.
#
# @see 1.3.0
#
# @api public
#
def self.extract(text)
return enum_for(:extract,text).to_a unless block_given?
scanner = StringScanner.new(text)
while scanner.skip_until(Regexp::EMAIL_ADDR)
yield parse(scanner.matched)
end
return nil
end
#
# Searches for email addresses associated with the given host names.
#
# @param [Array, String] names
# The host name(s) to search for.
#
# @return [Array]
# The matching email addresses.
#
# @since 1.0.0
#
# @api public
#
def self.with_hosts(names)
all('host_name.address' => names)
end
#
# Searches for email addresses associated with the given IP address(es).
#
# @param [Array, String] ips
# The IP address(es) to search for.
#
# @return [Array]
# The matching email addresses.
#
# @since 1.0.0
#
# @api public
#
def self.with_ips(ips)
all('ip_addresses.address' => ips)
end
#
# Searches for email addresses associated with the given user names.
#
# @param [Array, String] names
# The user name(s) to search for.
#
# @return [Array]
# The matching email addresses.
#
# @since 1.0.0
#
# @api public
#
def self.with_users(names)
all('user_name.name' => names)
end
#
# Parses an email address.
#
# @param [String] email
# The email address to parse.
#
# @return [EmailAddress]
# A new or previously saved email address resource.
#
# @raise [RuntimeError]
# The email address did not have a user name or a host name.
#
# @since 1.0.0
#
# @api public
#
def self.parse(email)
user, host = email.split('@',2)
user.strip!
if user.empty?
raise("email address #{email.dump} must have a user name")
end
host.strip!
if host.empty?
raise("email address #{email.dump} must have a host name")
end
return first_or_new(
:user_name => UserName.first_or_new(:name => user),
:host_name => HostName.first_or_new(:address => host)
)
end
#
# Creates a new Email Address.
#
# @param [URI::MailTo, #to_s] email
# The URI or String to create the Email Address from.
#
# @return [EmailAddress]
# The new Email Address.
#
# @since 1.4.0
#
# @api public
#
def self.from(email)
email = case email
when URI::MailTo
email.to
else
email.to_s
end
return parse(email)
end
#
# The user of the email address.
#
# @return [String]
# The user name.
#
# @since 1.0.0
#
# @api public
#
def user
self.user_name.name if self.user_name
end
#
# The host of the email address.
#
# @return [String]
# The host name.
#
# @since 1.0.0
#
# @api public
#
def host
self.host_name.address if self.host_name
end
#
# Converts the email address into a String.
#
# @return [String]
# The raw email address.
#
# @since 1.0.0
#
# @api public
#
def to_s
"#{self.user_name}@#{self.host_name}"
end
#
# Inspects the email address.
#
# @return [String]
# The inspected email address.
#
# @since 1.0.0
#
# @api public
#
def inspect
"#<#{self.class}: #{self}>"
end
#
# Splats the email address into multiple variables.
#
# @return [Array]
# The user-name and the host-name within the email address.
#
# @example
# email = EmailAddress.parse('alice@example.com')
# user, host = email
#
# user
# # => "alice"
# host
# # => "example.com"
#
# @since 1.0.0
#
# @api public
#
def to_ary
[self.user_name.name, self.host_name.address]
end
end
end