Module: EmailAddress::Rewriter
- Included in:
- Address
- Defined in:
- lib/email_address/rewriter.rb
Constant Summary collapse
- SRS_FORMAT_REGEX =
/\ASRS0=(....)=(\w\w)=(.+?)=(.+?)@(.+)\z/
- PRVS_REGEX =
/\Aprvs=(\d)(\d{3})(\w{6})=(.+)\z/
Instance Method Summary collapse
-
#batv_prvs(options = {}) ⇒ Object
————————————————————————— Returns a BATV form email address with “Private Signature” (prvs).
- #parse_prvs(email, options = {}) ⇒ Object
- #parse_rewritten(e) ⇒ Object
- #parse_srs(email, options = {}, &block) ⇒ Object
- #prvs_day(days) ⇒ Object
- #prvs_sign(k, ddd, email, options = {}) ⇒ Object
-
#srs(sending_domain, options = {}, &block) ⇒ Object
————————————————————————— SRS (Sender Rewriting Scheme) allows an address to be forwarded from the original owner and encoded to be used with the domain name of the MTA (Mail Transport Agent).
- #srs?(email) ⇒ Boolean
- #srs_hash(email, options = {}, &block) ⇒ Object
-
#srs_tt(t = Time.now.utc) ⇒ Object
SRS Timeout Token Returns a 2-character code for the day.
-
#verp(recipient, split_char = '+') ⇒ Object
————————————————————————— VERP Embeds a recipient email address into the bounce address Bounce Address: [email protected] Recipient Email: [email protected] VERP : [email protected] To handle incoming verp, the “tag” is the recipient email address, remember to convert the last ‘=’ into a ‘@’ to reconstruct it.
Instance Method Details
#batv_prvs(options = {}) ⇒ Object
Returns a BATV form email address with “Private Signature” (prvs). Options: key: 0-9 key digit to use
key_0..key_9: secret key used to sign/verify
prvs_days: number of days before address "expires"
BATV - Bounce Address Tag Validation PRVS - Simple Private Signature Ex: [email protected]
* K: Digit for Key rotation
* DDD: Expiry date, since 1970, low 3 digits
* SSSSSS: sha1( KDDD + orig-mailfrom + key)[0,6]
See: tools.ietf.org/html/draft-levine-smtp-batv-01
88 89 90 91 92 93 94 |
# File 'lib/email_address/rewriter.rb', line 88 def batv_prvs(={}) k = [:prvs_key_id] || "0" prvs_days = [:prvs_days] || @config[:prvs_days] || 30 ddd = prvs_day(prvs_days) ssssss = prvs_sign(k, ddd, self.to_s, ={}) ["prvs=", k, ddd, ssssss, '=', self.to_s].join('') end |
#parse_prvs(email, options = {}) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/email_address/rewriter.rb', line 98 def parse_prvs(email, ={}) if email.match(PRVS_REGEX) @rewrite_scheme = :prvs k, ddd, ssssss, email = [$1, $2, $3, $4] unless ssssss == prvs_sign(k, ddd, email, ) @rewrite_error = "Invalid BATV Address: Signature unverified" end exp = ddd.to_i roll = 1000 - exp # rolling 1000 day window today = prvs_day(0) # I'm sure this is wrong if exp > today && exp < roll @rewrite_error = "Invalid SRS Email Address: Address expired" elsif exp < today && (today - exp) > 0 @rewrite_error = "Invalid SRS Email Address: Address expired" end [local, domain].join("@") else email end end |
#parse_rewritten(e) ⇒ Object
9 10 11 12 13 14 15 |
# File 'lib/email_address/rewriter.rb', line 9 def parse_rewritten(e) @rewrite_scheme = nil @rewrite_error = nil e = parse_srs(e) # e = parse_batv(e) e end |
#parse_srs(email, options = {}, &block) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/email_address/rewriter.rb', line 39 def parse_srs(email, ={}, &block) if email && email.match(SRS_FORMAT_REGEX) @rewrite_scheme = :srs hhh, tt, domain, local, sending_domain = [$1, $2, $3, $4, $5] hhh = tt = sending_domain if false && hhh # Hide warnings for now :-) a = [tt, domain, local].join("=") + "@" + sending_domain unless srs_hash(a, , &block) === hhh @rewrite_error = "Invalid SRS Email Address: Possibly altered" end unless tt == srs_tt @rewrite_error = "Invalid SRS Email Address: Too old" end [local, domain].join("@") else email end end |
#prvs_day(days) ⇒ Object
121 122 123 |
# File 'lib/email_address/rewriter.rb', line 121 def prvs_day(days) ((Time.now.to_i + (days*24*60*60)) / (24*60*60)).to_s[-3,3] end |
#prvs_sign(k, ddd, email, options = {}) ⇒ Object
125 126 127 128 129 |
# File 'lib/email_address/rewriter.rb', line 125 def prvs_sign(k, ddd, email, ={}) str = [ddd, ssssss, '=', self.to_s].join('') key = ["key_#{k}".to_i] || @config["key_#{k}".to_i] || str.reverse Digest::SHA1.hexdigest([k,ddd, email, key].join(''))[0,6] end |
#srs(sending_domain, options = {}, &block) ⇒ Object
SRS (Sender Rewriting Scheme) allows an address to be forwarded from the original owner and encoded to be used with the domain name of the MTA (Mail Transport Agent). It encodes the original address within the local part of the sending email address and respects VERP. If example.com needs to forward a message from “[email protected]”, the SMTP envelope sender is used at this address. These methods respect DMARC and prevent spoofing email send using a different domain. Format: [email protected]
27 28 29 30 31 32 33 |
# File 'lib/email_address/rewriter.rb', line 27 def srs(sending_domain, ={}, &block) tt = srs_tt() a = [tt, self.hostname, self.local.to_s].join("=") + "@" + sending_domain hhh = srs_hash(a, , &block) ["SRS0", hhh, a].join("=") end |
#srs?(email) ⇒ Boolean
35 36 37 |
# File 'lib/email_address/rewriter.rb', line 35 def srs?(email) email.match(SRS_FORMAT_REGEX) ? true : false end |
#srs_hash(email, options = {}, &block) ⇒ Object
65 66 67 68 69 70 71 72 |
# File 'lib/email_address/rewriter.rb', line 65 def srs_hash(email, ={}, &block) key = [:key] || @config[:key] || email.reverse if block_given? block.call(email)[0,4] else Base64.encode64(Digest::SHA1.digest(email + key))[0,4] end end |
#srs_tt(t = Time.now.utc) ⇒ Object
SRS Timeout Token Returns a 2-character code for the day. After a few days the code will roll. TT has a one-day resolution in order to make the address invalid after a few days. The cycle period is 3.5 years. Used to control late bounces and harvesting.
61 62 63 |
# File 'lib/email_address/rewriter.rb', line 61 def srs_tt(t=Time.now.utc) Base64.encode64((t.to_i / (60*60*24) % 210).to_s)[0,2] end |
#verp(recipient, split_char = '+') ⇒ Object
VERP Embeds a recipient email address into the bounce address
Bounce Address: [email protected]
Recipient Email: [email protected]
VERP : [email protected]
To handle incoming verp, the “tag” is the recipient email address, remember to convert the last ‘=’ into a ‘@’ to reconstruct it.
139 140 141 142 143 |
# File 'lib/email_address/rewriter.rb', line 139 def verp(recipient, split_char='+') self.local.to_s + split_char + recipient.gsub("@","=") + "@" + self.hostname end |