mailgun_webhooks 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.md +45 -0
- data/Rakefile +27 -0
- data/lib/mailgun_webhooks.rb +68 -0
- data/lib/mailgun_webhooks/rack.rb +21 -0
- data/lib/mailgun_webhooks/rails/railtie.rb +9 -0
- data/lib/mailgun_webhooks/signature.rb +22 -0
- data/lib/mailgun_webhooks/version.rb +3 -0
- data/lib/mailgun_webhooks/webhook_registry.rb +23 -0
- metadata +93 -0
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2012 Michael Guterl
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Mailgun Webhooks
|
|
2
|
+
|
|
3
|
+
Add support for acting on Mailgun webhooks to your Rack or Rails application.
|
|
4
|
+
|
|
5
|
+
## Rails Installation
|
|
6
|
+
|
|
7
|
+
Add `gem 'mailgun_webhooks'` to your Gemfile.
|
|
8
|
+
|
|
9
|
+
Setup `config/initializers/mailgun.rb`
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
MailgunWebhooks.api_key = "yourapikeyfrommailgun"
|
|
13
|
+
MailgunWebhooks.api_host = "yourdomain.com"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Rack Installation
|
|
17
|
+
|
|
18
|
+
If you wish to use MailgunWebhooks outside of Rails, you can leverage the same middleware used to provide Rails integration. Just add `MailgunWebhooks::App` to your middleware stack.
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
use MailgunWebhooks::App
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Webhooks
|
|
25
|
+
|
|
26
|
+
By default your application will listen for webhook payloads on `/mailgun`. You can change this by setting `MailgunWebhooks.endpoint`.
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
MailgunWebhooks.endpoint = '/mailgun_webhooks'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
In order to customize how your application reacts to webhooks you can define the behavior using `Mailgun.on`.
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
MailgunWebhooks.on(:bounced) do |data|
|
|
36
|
+
# Do something with the incoming data. Check the documentation for details:
|
|
37
|
+
# http://documentation.mailgun.net/user_manual.html#events-webhooks
|
|
38
|
+
|
|
39
|
+
if (user = User.find_by_email(data['recipient'])
|
|
40
|
+
user.update_attribute(:email_bounced_at, Time.now)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**NOTE** It is important to recognize that the hash passed to the block is just a Hash and not a HashWithIndifferentAccess so you have to access the keys as strings, not symbols.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
begin
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'rdoc/rdoc'
|
|
11
|
+
require 'rake/rdoctask'
|
|
12
|
+
RDoc::Task = Rake::RDocTask
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'MailgunWebhooks'
|
|
18
|
+
rdoc.options << '--line-numbers'
|
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Bundler::GemHelper.install_tasks
|
|
24
|
+
|
|
25
|
+
require 'rspec/core/rake_task'
|
|
26
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
27
|
+
task :default => :spec
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'mailgun_webhooks/signature'
|
|
2
|
+
require 'mailgun_webhooks/webhook_registry'
|
|
3
|
+
require 'mailgun_webhooks/rack'
|
|
4
|
+
|
|
5
|
+
if defined? ::Rails
|
|
6
|
+
require 'mailgun_webhooks/rails/railtie'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module MailgunWebhooks
|
|
10
|
+
# Public: Base class for any errors raised from within MailgunWebhooks.
|
|
11
|
+
Error = Class.new(StandardError)
|
|
12
|
+
|
|
13
|
+
# Public: Error raised when signature is invalid.
|
|
14
|
+
InvalidSignature = Class.new(Error)
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Public: The Mailgun API key.
|
|
18
|
+
#
|
|
19
|
+
# Returns a String.
|
|
20
|
+
attr_accessor :api_key
|
|
21
|
+
|
|
22
|
+
# Public: The Mailgun API host.
|
|
23
|
+
#
|
|
24
|
+
# Returns a String.
|
|
25
|
+
attr_accessor :api_host
|
|
26
|
+
|
|
27
|
+
# Public: The endpoint for webhooks.
|
|
28
|
+
#
|
|
29
|
+
# Returns a String.
|
|
30
|
+
attr_accessor :endpoint
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Set default endpoint.
|
|
34
|
+
self.endpoint = '/mailgun'
|
|
35
|
+
|
|
36
|
+
# Make MailgunWebhooks behave like a singleton.
|
|
37
|
+
extend self
|
|
38
|
+
|
|
39
|
+
# Public: Add a webhook to the registry.
|
|
40
|
+
#
|
|
41
|
+
# Returns nothing.
|
|
42
|
+
def on(webhook, &block)
|
|
43
|
+
webhooks.on(webhook, &block)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Public: Verify the signature of the data and trigger the webhook if it is
|
|
47
|
+
# valid. Raise InvalidSignature if the data signature is not valid.
|
|
48
|
+
#
|
|
49
|
+
# Returns nothing.
|
|
50
|
+
def trigger(webhook, data)
|
|
51
|
+
raise InvalidSignature unless verify_signature(data)
|
|
52
|
+
|
|
53
|
+
webhooks.trigger(webhook, data)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Public: Helper method to check the validity of the data.
|
|
57
|
+
#
|
|
58
|
+
# Returns a boolean.
|
|
59
|
+
def verify_signature(data)
|
|
60
|
+
Signature.valid?(data.merge(:api_key => api_key))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Internal: A WebhookRegistry instance.
|
|
64
|
+
def webhooks
|
|
65
|
+
@webhooks ||= WebhookRegistry.new
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module MailgunWebhooks
|
|
2
|
+
class Rack
|
|
3
|
+
|
|
4
|
+
def initialize(app)
|
|
5
|
+
@app = app
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def call(env)
|
|
9
|
+
request = ::Rack::Request.new(env)
|
|
10
|
+
params = request.params
|
|
11
|
+
|
|
12
|
+
if request.path == MailgunWebhooks.endpoint
|
|
13
|
+
MailgunWebhooks.trigger(params['event'], params)
|
|
14
|
+
[200, {}, []]
|
|
15
|
+
else
|
|
16
|
+
@app.call(env)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
|
|
3
|
+
module MailgunWebhooks
|
|
4
|
+
class Signature
|
|
5
|
+
# Public: Verifies the incoming data according to the MailgunWebhooks specs:
|
|
6
|
+
# http://documentation.mailgun.net/user_manual.html#events-webhooks
|
|
7
|
+
#
|
|
8
|
+
# Returns a boolean.
|
|
9
|
+
def self.valid?(data)
|
|
10
|
+
signature = data.fetch('signature')
|
|
11
|
+
api_key = data.fetch('api_key')
|
|
12
|
+
timestamp = data.fetch('timestamp')
|
|
13
|
+
token = data.fetch('token')
|
|
14
|
+
digest = OpenSSL::Digest::Digest.new('sha256')
|
|
15
|
+
|
|
16
|
+
signature == OpenSSL::HMAC.hexdigest(digest,
|
|
17
|
+
api_key,
|
|
18
|
+
'%s%s' % [timestamp, token])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module MailgunWebhooks
|
|
2
|
+
class WebhookRegistry
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@hooks = Hash.new { |h, k| h[k] = [] }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Public: Store a block by name for later execution.
|
|
9
|
+
#
|
|
10
|
+
# Returns nothing.
|
|
11
|
+
def on(webhook, &block)
|
|
12
|
+
@hooks[webhook.to_sym] << block
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Public: Execute all of the blocks associated with the webhook.
|
|
16
|
+
#
|
|
17
|
+
# Returns nothing.
|
|
18
|
+
def trigger(webhook, data)
|
|
19
|
+
@hooks[webhook.to_sym].each { |hook| hook.call data }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mailgun_webhooks
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Michael Guterl
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-05-03 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rails
|
|
16
|
+
requirement: &70309673687320 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 3.2.3
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *70309673687320
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: sqlite3
|
|
27
|
+
requirement: &70309673686900 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ! '>='
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *70309673686900
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: rspec-rails
|
|
38
|
+
requirement: &70309673686440 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ! '>='
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
type: :development
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *70309673686440
|
|
47
|
+
description: Easily add Mailgun Webhook integration to your Rails or Rack application.
|
|
48
|
+
email:
|
|
49
|
+
- michael@diminishing.org
|
|
50
|
+
executables: []
|
|
51
|
+
extensions: []
|
|
52
|
+
extra_rdoc_files: []
|
|
53
|
+
files:
|
|
54
|
+
- lib/mailgun_webhooks/rack.rb
|
|
55
|
+
- lib/mailgun_webhooks/rails/railtie.rb
|
|
56
|
+
- lib/mailgun_webhooks/signature.rb
|
|
57
|
+
- lib/mailgun_webhooks/version.rb
|
|
58
|
+
- lib/mailgun_webhooks/webhook_registry.rb
|
|
59
|
+
- lib/mailgun_webhooks.rb
|
|
60
|
+
- MIT-LICENSE
|
|
61
|
+
- Rakefile
|
|
62
|
+
- README.md
|
|
63
|
+
homepage: http://github.com/mguterl/mailgun_webhooks
|
|
64
|
+
licenses: []
|
|
65
|
+
post_install_message:
|
|
66
|
+
rdoc_options: []
|
|
67
|
+
require_paths:
|
|
68
|
+
- lib
|
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
|
+
none: false
|
|
71
|
+
requirements:
|
|
72
|
+
- - ! '>='
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
segments:
|
|
76
|
+
- 0
|
|
77
|
+
hash: -3481488083271243959
|
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
|
+
none: false
|
|
80
|
+
requirements:
|
|
81
|
+
- - ! '>='
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
segments:
|
|
85
|
+
- 0
|
|
86
|
+
hash: -3481488083271243959
|
|
87
|
+
requirements: []
|
|
88
|
+
rubyforge_project:
|
|
89
|
+
rubygems_version: 1.8.17
|
|
90
|
+
signing_key:
|
|
91
|
+
specification_version: 3
|
|
92
|
+
summary: Rails and Rack integration for Mailgun Webhooks
|
|
93
|
+
test_files: []
|