Revision 2891e0c2
Added by Marc Dequènes almost 16 years ago
- ID 2891e0c2f55f7c42efb4be061ef2545b0797289b
lib/tmail_extra.rb | ||
---|---|---|
# attempt to check PGP signature in a RFC3156-compliant way
|
||
module TMail
|
||
class Mail
|
||
def is_pgp_signed?
|
||
content_type == "multipart/signed" and parts.size == 2 and parts[1].content_type == "application/pgp-signature"
|
||
end
|
||
|
||
def pgp_signature
|
||
return nil unless is_pgp_signed?
|
||
parts[1].decoded
|
||
end
|
||
|
||
def pgp_signed_part
|
||
return nil unless is_pgp_signed?
|
||
parts[0]
|
||
end
|
||
|
||
def verify_pgp_signature
|
||
return nil unless is_pgp_signed?
|
||
|
||
# using RAW part, without any decoding
|
||
# remove last EOL due to MIME protocol and properly convert all EOL to CRLF
|
||
content = parts[0].raw.chomp.gsub(/\r?\n/, "\r\n")
|
||
sig = pgp_signature()
|
||
|
||
logger.debug "Proper signed content detected"
|
||
sig_check = nil
|
||
GPGME::verify(sig, content) do |signature|
|
||
sig_check = signature
|
||
end
|
||
|
||
sig_check
|
||
end
|
||
|
||
protected
|
||
|
||
def raw
|
||
@port.read_all
|
||
end
|
||
end
|
||
end
|
postman | ||
---|---|---|
require 'log4r'
|
||
require 'net/imap'
|
||
require 'tmail'
|
||
require 'tmail_extra'
|
||
#require 'socket'
|
||
#require 'fileutils'
|
||
#require 'tempfile'
|
||
... | ... | |
|
||
#Socket.gethostname
|
||
|
||
# needed to verify _untouched_ signed MIME part
|
||
module TMail
|
||
class Mail
|
||
def raw
|
||
@port.read_all
|
||
end
|
||
end
|
||
end
|
||
|
||
#
|
||
# TODO:
|
||
# - should be able to handle encrypted messages for user to send sensitive data (postman would need a GPG key too)
|
||
... | ... | |
#imap = Net::IMAP.new('imap.duckcorp.org', 993, true, "/etc/ssl/certs/duckcorp.crt", true)
|
||
imap = Net::IMAP.new('localhost')
|
||
logger.debug "Connected to IMAP server"
|
||
logger.debug imap.capability()
|
||
logger.debug "IMAP Capabilities: " + imap.capability.join(", ")
|
||
imap.authenticate('LOGIN', @config.imap.login, @config.imap.passwd)
|
||
logger.debug "Logged into IMAP account"
|
||
#p imap.getquotaroot("INBOX")
|
||
... | ... | |
logger.set_prefix("[#{mail.message_id}] ")
|
||
logger.info "#{mail.from_addrs} -> #{mail.to_addrs}: #{mail.subject}"
|
||
# ignore mails not signed
|
||
unless mail.content_type == "multipart/signed" and mail.parts.size == 2 and mail.parts[1].content_type == "application/pgp-signature"
|
||
unless mail.is_pgp_signed?
|
||
logger.info "Mail not signed or not RFC3156 compliant"
|
||
next
|
||
end
|
||
|
||
content = mail.parts[0].raw.chomp.gsub(/\r?\n/, "\r\n")
|
||
decoded_content = mail.parts[0].body
|
||
sig = mail.parts[1].decoded
|
||
decoded_content = mail.pgp_signed_part().body
|
||
|
||
logger.debug "Proper signed content detected"
|
||
GPGME::verify(sig, content) do |signature|
|
||
if signature.status == 0
|
||
logger.info "Mail content was properly signed by key #{signature.fingerprint}"
|
||
list = Person.find(:all, :attribute => 'keyFingerPrint', :value => signature.fingerprint)
|
||
case list.size
|
||
when 0
|
||
logger.info "Mail is from an unknow person"
|
||
when 1
|
||
user = list.first
|
||
logger.info "Mail is from user #{user.uid} (#{user.cn})"
|
||
CommandParser.run(user, decoded_content)
|
||
else
|
||
logger.warn "Multiple users match in database, so i guess there is a mistake. It is safer to skip..."
|
||
end
|
||
else
|
||
logger.info "Mail content tampered or badly signed: " + signature.to_s
|
||
end
|
||
sig_check = mail.verify_pgp_signature()
|
||
if sig_check.status == 0
|
||
logger.info "Mail content was properly signed by key #{sig_check.fingerprint}"
|
||
list = Person.find(:all, :attribute => 'keyFingerPrint', :value => sig_check.fingerprint)
|
||
case list.size
|
||
when 0
|
||
logger.info "Mail is from an unknow person"
|
||
when 1
|
||
user = list.first
|
||
logger.info "Mail is from user #{user.uid} (#{user.cn})"
|
||
CommandParser.run(user, decoded_content)
|
||
else
|
||
logger.warn "Multiple users match in database, so i guess there is a mistake. It is safer to skip..."
|
||
end
|
||
else
|
||
logger.info "Mail content tampered or badly signed: " + sig_check.to_s
|
||
end
|
||
end
|
||
imap.logout
|
Also available in: Unified diff
[evol] properly moved tmail signature handling out of postman in a library (which i should probably suggest upstream)