مراية لـ
https://github.com/postalserver/postal.git
تم المزامنة 2026-01-18 05:49:47 +00:00
88 أسطر
2.6 KiB
Ruby
88 أسطر
2.6 KiB
Ruby
module Postal
|
|
class DKIMHeader
|
|
|
|
def initialize(domain, message)
|
|
if domain && domain.dkim_status == 'OK'
|
|
@domain_name = domain.name
|
|
@dkim_key = domain.dkim_key
|
|
@dkim_identifier = domain.dkim_identifier
|
|
else
|
|
@domain_name = Postal.config.dns.return_path
|
|
@dkim_key = Postal.signing_key
|
|
@dkim_identifier = 'postal'
|
|
end
|
|
@domain = domain
|
|
@message = message
|
|
@raw_headers, @raw_body = @message.split(/\r?\n\r?\n/, 2)
|
|
end
|
|
|
|
def dkim_header
|
|
"DKIM-Signature: v=1;" + dkim_properties + signature
|
|
end
|
|
|
|
private
|
|
|
|
def headers
|
|
@headers ||= @raw_headers.to_s.gsub(/\r?\n\s/, ' ').split(/\r?\n/)
|
|
end
|
|
|
|
def header_names
|
|
normalized_headers.map{ |h| h.split(':')[0].strip }
|
|
end
|
|
|
|
def normalized_headers
|
|
Array.new.tap do |new_headers|
|
|
headers.select { |h| h.match(/^(to|from|date|subject|message-id):/i) }.each do |h|
|
|
new_headers << normalize_header(h)
|
|
end
|
|
end
|
|
end
|
|
|
|
def normalize_header(content)
|
|
content.gsub!(/[ \t]+/, ' ') # Tidy whitespace
|
|
key, value = content.split(':', 2).map{ |a| a.strip } # Split into key/value and strip whitespace
|
|
key.downcase! # Downcase the key
|
|
key + ':' + value # Rejoin
|
|
end
|
|
|
|
def normalized_body
|
|
@normalized_body ||= begin
|
|
content = @raw_body.dup
|
|
content.gsub!("\r", '') # Make sure we have no random CRs
|
|
content.gsub!("\n", "\r\n") # Convert to CRLF
|
|
content.gsub!(/[ \t]+/, ' ') # Tidy whitespace
|
|
content.gsub!(" \r\n", "\r\n") # Remove trailing whitespace
|
|
content.gsub!(/(\r\n)+\z/, "") # Remove trailing lines
|
|
content.gsub!(/\z/, "\r\n") # Add a final newline
|
|
content
|
|
end
|
|
end
|
|
|
|
def body_hash
|
|
@body_hash ||= Base64.encode64(Digest::SHA256.digest(normalized_body)).strip
|
|
end
|
|
|
|
def dkim_properties
|
|
String.new.tap do |header|
|
|
header << " a=rsa-sha256; c=relaxed/relaxed;"
|
|
header << " d=#{@domain_name}; s=#{@dkim_identifier}; t=#{Time.now.utc.to_i};"
|
|
header << " bh=#{body_hash}; h=#{header_names.join(':')};"
|
|
header << " b="
|
|
end
|
|
end
|
|
|
|
def dkim_header_for_signing
|
|
"dkim-signature:v=1;" + dkim_properties
|
|
end
|
|
|
|
def signable_header_string
|
|
(normalized_headers + [dkim_header_for_signing]).join("\r\n")
|
|
end
|
|
|
|
def signature
|
|
Base64.encode64(@dkim_key.sign(OpenSSL::Digest::SHA256.new, signable_header_string)).gsub("\n", '')
|
|
end
|
|
|
|
end
|
|
end
|