2016-05-30 17:11:17 +02:00
require " openssl "
class WebhooksController < ActionController :: Base
def mailgun
# can't verify data without an API key
return mailgun_failure if SiteSetting . mailgun_api_key . blank?
# token is a random string of 50 characters
2016-06-09 00:33:13 +02:00
token = params [ " token " ]
2016-05-30 17:11:17 +02:00
return mailgun_failure if token . blank? || token . size != 50
# prevent replay attack
key = " mailgun_token_ #{ token } "
return mailgun_failure unless $redis . setnx ( key , 1 )
2016-06-08 22:38:38 +02:00
$redis . expire ( key , 10 . minutes )
2016-05-30 17:11:17 +02:00
# ensure timestamp isn't too far from current time
2016-06-09 00:33:13 +02:00
timestamp = params [ " timestamp " ]
2016-06-08 22:38:38 +02:00
return mailgun_failure if ( Time . at ( timestamp . to_i ) - Time . now ) . abs > 24 . hours . to_i
2016-05-30 17:11:17 +02:00
# check the signature
return mailgun_failure unless mailgun_verify ( timestamp , token , params [ " signature " ] )
2016-06-09 00:33:13 +02:00
event = params [ " event " ]
message_id = params [ " Message-Id " ] . tr ( " <> " , " " )
2016-05-30 17:11:17 +02:00
# only handle soft bounces, because hard bounces are also handled
# by the "dropped" event and we don't want to increase bounce score twice
# for the same message
if event == " bounced " . freeze && params [ " error " ] [ " 4. " ]
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: SOFT_BOUNCE_SCORE )
2016-05-30 17:11:17 +02:00
elsif event == " dropped " . freeze
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: HARD_BOUNCE_SCORE )
2016-05-30 17:11:17 +02:00
end
2016-06-08 22:38:38 +02:00
mailgun_success
2016-05-30 17:11:17 +02:00
end
2016-06-01 21:48:06 +02:00
def sendgrid
2016-06-06 19:47:45 +02:00
events = params [ " _json " ] || [ params ]
events . each do | event |
2016-06-08 22:38:38 +02:00
message_id = ( event [ " smtp-id " ] || " " ) . tr ( " <> " , " " )
2016-06-01 21:48:06 +02:00
if event [ " event " ] == " bounce " . freeze
if event [ " status " ] [ " 4. " ]
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: SOFT_BOUNCE_SCORE )
2016-06-01 21:48:06 +02:00
else
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: HARD_BOUNCE_SCORE )
2016-06-01 21:48:06 +02:00
end
elsif event [ " event " ] == " dropped " . freeze
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: HARD_BOUNCE_SCORE )
2016-06-01 21:48:06 +02:00
end
end
render nothing : true , status : 200
end
2016-06-06 19:47:45 +02:00
def mailjet
events = params [ " _json " ] || [ params ]
events . each do | event |
2016-06-08 22:38:38 +02:00
message_id = event [ " CustomID " ]
2016-06-06 19:47:45 +02:00
if event [ " event " ] == " bounce " . freeze
if event [ " hard_bounce " ]
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: HARD_BOUNCE_SCORE )
2016-06-06 19:47:45 +02:00
else
2016-06-08 22:38:38 +02:00
process_bounce ( message_id , Email :: Receiver :: SOFT_BOUNCE_SCORE )
2016-06-06 19:47:45 +02:00
end
end
end
render nothing : true , status : 200
end
2016-06-13 12:31:01 +02:00
def mandrill
events = params [ " mandrill_events " ]
events . each do | event |
message_id = event [ " msg " ] [ " metadata " ] [ " message_id " ] rescue nil
next unless message_id
case event [ " event " ]
when " hard_bounce "
process_bounce ( message_id , Email :: Receiver :: HARD_BOUNCE_SCORE )
when " soft_bounce "
process_bounce ( message_id , Email :: Receiver :: SOFT_BOUNCE_SCORE )
end
end
render nothing : true , status : 200
end
2016-05-30 17:11:17 +02:00
private
def mailgun_failure
render nothing : true , status : 406
end
def mailgun_success
render nothing : true , status : 200
end
def mailgun_verify ( timestamp , token , signature )
digest = OpenSSL :: Digest :: SHA256 . new
data = " #{ timestamp } #{ token } "
signature == OpenSSL :: HMAC . hexdigest ( digest , SiteSetting . mailgun_api_key , data )
end
2016-06-08 22:38:38 +02:00
def process_bounce ( message_id , bounce_score )
2016-06-06 19:47:45 +02:00
return if message_id . blank?
email_log = EmailLog . find_by ( message_id : message_id )
return if email_log . nil?
email_log . update_columns ( bounced : true )
Email :: Receiver . update_bounce_score ( email_log . user . email , bounce_score )
end
2016-05-30 17:11:17 +02:00
end