Class: MailAutoLinkObfuscation::AutoLinkObfuscator

Inherits:
Object
  • Object
show all
Defined in:
lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb

Constant Summary collapse

AUTO_LINKED_EMAIL_PATTERN =
/[\w\.%+-]+@[\w-]+(?:\.[\w-]+)+/
AUTO_LINKED_URL_PATTERN =
%r{(?:(?:\w+:)?//[\w-]+(?:\.[\w-]+)*|[\w-]+(?:\.[\w-]+)*\.\w{2,}(?!\.\w))\S*}
AUTO_LINKED_PATTERN =
Regexp.new([AUTO_LINKED_EMAIL_PATTERN, AUTO_LINKED_URL_PATTERN].join('|'))
KEY_CHARS =
%r{[@.]+|:*//+}

Instance Method Summary collapse

Constructor Details

#initialize(mail, options) ⇒ AutoLinkObfuscator

Returns a new instance of AutoLinkObfuscator.



12
13
14
15
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 12

def initialize(mail, options)
  @mail = mail
  @options = options || {}
end

Instance Method Details



32
33
34
35
36
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 32

def extract_link_whitelist_from(doc)
  return Set.new unless doc
  whitelist = doc.xpath('//@href').map { |href| href.content.sub(/\Amailto:|[?#].*\z/, '') }.to_set
  whitelist.merge(whitelist.map { |href| href.sub(%r{\A\w+://}, '') })
end


26
27
28
29
30
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 26

def extract_link_whitelist_from_html
  @link_whitelist =
    extract_link_whitelist_from(html_body_doc) +
    extract_link_whitelist_from(html_part_doc)
end

#html_body_docObject



38
39
40
41
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 38

def html_body_doc
  return unless @mail.content_type.include? 'text/html'
  @html_body_doc ||= Nokogiri::HTML(@mail.decoded)
end

#html_part_docObject



43
44
45
46
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 43

def html_part_doc
  return unless @mail.html_part
  @html_part_doc ||= Nokogiri::HTML(@mail.html_part.decoded)
end

#runObject



17
18
19
20
21
22
23
24
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 17

def run
  extract_link_whitelist_from_html
  transform_html_body if @mail.content_type.include? 'text/html'
  transform_text_body if @mail.content_type.include? 'text/plain'
  transform_html_part if @mail.html_part
  transform_text_part if @mail.text_part
  @mail
end

#transform_auto_linked_pattern(text) ⇒ Object



80
81
82
83
84
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 80

def transform_auto_linked_pattern(text)
  text.gsub(AUTO_LINKED_PATTERN) do |match|
    @link_whitelist.any? { |whitelisted_link| match.start_with?(whitelisted_link) } ? match : yield(match)
  end
end

#transform_html(doc) ⇒ Object



56
57
58
59
60
61
62
63
64
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 56

def transform_html(doc)
  doc.xpath('//body/descendant::text()').each do |node|
    next if node.parent&.name == 'script'
    text = CGI.escapeHTML(node.content)
    node.replace(transform_text(text))
  end

  doc.to_s
end

#transform_html_bodyObject



48
49
50
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 48

def transform_html_body
  @mail.body = transform_html(html_body_doc)
end

#transform_html_partObject



52
53
54
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 52

def transform_html_part
  @mail.html_part.body = transform_html(html_part_doc)
end

#transform_text(text) ⇒ Object



74
75
76
77
78
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 74

def transform_text(text)
  transform_auto_linked_pattern(text) do |match|
    match.gsub(KEY_CHARS, "\u200C\\0\u200C")
  end
end

#transform_text_bodyObject



66
67
68
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 66

def transform_text_body
  @mail.body = transform_text(@mail.decoded)
end

#transform_text_partObject



70
71
72
# File 'lib/mail_auto_link_obfuscation/auto_link_obfuscator.rb', line 70

def transform_text_part
  @mail.text_part.body = transform_text(@mail.text_part.decoded)
end