Class: Jekyll::EmailMunge::MungeEmailTag

Inherits:
Liquid::Tag
  • Object
show all
Defined in:
lib/jekyll-email-munge/munge_email_tag.rb

Overview

munge_email “user@example.com” % munge_email “user@example.com” “Get|in touch” %

Renders a “munged” mailto link at build time. The address is encrypted with AES-128-GCM (key from _config.yml -> email_munge.key_hex) so only ciphertext appears in the served HTML. A CSS-hidden decoy span sits inside the link and a <noscript> inline-SVG fallback handles JS-disabled visitors.

The “|” in the visible text marks where the decoy span is injected. Default text is “Reach|out” -> “Reach<decoy/> out”.

Naming convention note:

The Liquid tag name (`munge_email`) and config key (`email_munge`) only
appear in source code, never in the served HTML. The rendered output
uses `liame` (`email` reversed) for every class/attribute a scraper
might regex for: class="liame", data-liame, .liame-decoy, .liame-svg.

See README for the companion munge_email_script % tag and CSS.

Constant Summary collapse

SYNTAX =
/^\s*"([^"]+)"(?:\s+"([^"]+)")?\s*$/.freeze

Instance Method Summary collapse

Constructor Details

#initialize(tag_name, markup, tokens) ⇒ MungeEmailTag

Returns a new instance of MungeEmailTag.



29
30
31
32
33
34
35
36
37
# File 'lib/jekyll-email-munge/munge_email_tag.rb', line 29

def initialize(tag_name, markup, tokens)
  super
  m = markup.match(SYNTAX)
  unless m
    raise SyntaxError, %(jekyll-email-munge: tag syntax is {% munge_email "email" ["visible|text"] %})
  end
  @email = m[1]
  @text = m[2] || "Reach|out"
end

Instance Method Details

#render(context) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/jekyll-email-munge/munge_email_tag.rb', line 39

def render(context)
  cfg = (context.registers[:site].config["email_munge"] || {})
  key_hex = cfg["key_hex"]
  unless key_hex
    raise "jekyll-email-munge: email_munge.key_hex missing in _config.yml. " \
          "Generate one with `ruby -ropenssl -e 'puts OpenSSL::Random.random_bytes(16).unpack1(\"H*\")'`"
  end
  unless key_hex =~ /\A[0-9a-fA-F]{32}\z/
    raise "jekyll-email-munge: email_munge.key_hex must be 32 hex characters (16 bytes / AES-128)"
  end

  decoy = cfg["decoy"] || "no-reply@spam.invalid"
  svg_color = cfg["svg_color"] || "#9c3f1d"

  payload = encrypt(@email, key_hex)
  before, after = split_text(@text)
  svg = inline_svg(@email, svg_color)

  esc = ->(s) { CGI.escapeHTML(s) }
  %(<a href="#" class="liame" data-liame="#{esc.call(payload)}" rel="nofollow">) +
    %(#{esc.call(before)}) +
    %(<span class="liame-decoy" aria-hidden="true">#{esc.call(decoy)}</span>) +
    %(#{esc.call(after)}</a>) +
    %(<noscript> (or use the address shown here: #{svg})</noscript>)
end