mailgun_webhooks 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,9 @@
1
+ module MailgunWebhooks
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ initializer "mailgun_webhooks.insert_middleware" do |app|
5
+ app.config.middleware.use "MailgunWebhooks::Rack"
6
+ end
7
+ end
8
+ end
9
+ 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,3 @@
1
+ module MailgunWebhooks
2
+ VERSION = "0.0.1"
3
+ 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: []